Implement an atabus control device, and define some ATA bus control

IOCTLS. Implement ATABUSIORESET, which will reset the given ATA bus.
This commit is contained in:
bouyer 2004-08-01 21:40:41 +00:00
parent b4ae48a794
commit 011181ac3e
8 changed files with 144 additions and 25 deletions

View File

@ -1,4 +1,4 @@
# $NetBSD: majors,v 1.9 2004/06/18 15:02:29 christos Exp $
# $NetBSD: majors,v 1.10 2004/08/01 21:40:41 bouyer Exp $
#
# Device majors for Machine-Independent drivers.
#
@ -15,3 +15,4 @@ device-major vinum char 162 block 162 vinum
device-major fss char 163 block 163 fss
device-major pps char 164 pps
device-major ptm char 165 pty
device-major atabus char 166 atabus

View File

@ -1,4 +1,4 @@
/* $NetBSD: ata.c,v 1.29 2004/05/27 02:23:12 thorpej Exp $ */
/* $NetBSD: ata.c,v 1.30 2004/08/01 21:40:41 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.29 2004/05/27 02:23:12 thorpej Exp $");
__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.30 2004/08/01 21:40:41 bouyer Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@ -41,9 +41,12 @@ __KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.29 2004/05/27 02:23:12 thorpej Exp $");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/device.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
#include <sys/kthread.h>
#include <sys/errno.h>
#include <sys/ataio.h>
#include <machine/intr.h>
#include <machine/bus.h>
@ -74,6 +77,18 @@ extern int wdcdebug_mask; /* init'ed in wdc.c */
* for drives, etc.
*****************************************************************************/
dev_type_open(atabusopen);
dev_type_close(atabusclose);
dev_type_ioctl(atabusioctl);
const struct cdevsw atabus_cdevsw = {
atabusopen, atabusclose, noread, nowrite, atabusioctl,
nostop, notty, nopoll, nommap, nokqfilter,
};
extern struct cfdriver atabus_cd;
/*
* atabusprint:
*
@ -481,3 +496,81 @@ ata_dmaerr(struct ata_drive_datas *drvp, int flags)
drvp->n_xfers = 1; /* restart counting from this error */
}
}
/* management of the /dev/atabus* devices */
int atabusopen(dev, flag, fmt, p)
dev_t dev;
int flag, fmt;
struct proc *p;
{
struct atabus_softc *sc;
int error, unit = minor(dev);
if (unit >= atabus_cd.cd_ndevs ||
(sc = atabus_cd.cd_devs[unit]) == NULL)
return (ENXIO);
if (sc->sc_flags & ATABUSCF_OPEN)
return (EBUSY);
if ((error = wdc_addref(sc->sc_chan)) != 0)
return (error);
sc->sc_flags |= ATABUSCF_OPEN;
return (0);
}
int
atabusclose(dev, flag, fmt, p)
dev_t dev;
int flag, fmt;
struct proc *p;
{
struct atabus_softc *sc = atabus_cd.cd_devs[minor(dev)];
wdc_delref(sc->sc_chan);
sc->sc_flags &= ~ATABUSCF_OPEN;
return (0);
}
int
atabusioctl(dev, cmd, addr, flag, p)
dev_t dev;
u_long cmd;
caddr_t addr;
int flag;
struct proc *p;
{
struct atabus_softc *sc = atabus_cd.cd_devs[minor(dev)];
int error;
int s;
/*
* Enforce write permission for ioctls that change the
* state of the bus. Host adapter specific ioctls must
* be checked by the adapter driver.
*/
switch (cmd) {
case ATABUSIOSCAN:
case ATABUSIODETACH:
case ATABUSIORESET:
if ((flag & FWRITE) == 0)
return (EBADF);
}
switch (cmd) {
case ATABUSIORESET:
s = splbio();
wdc_reset_channel(sc->sc_chan, AT_WAIT | AT_POLL);
splx(s);
error = 0;
break;
default:
error = ENOTTY;
}
return (error);
};

View File

@ -1,4 +1,4 @@
/* $NetBSD: ata_wdc.c,v 1.58 2004/07/31 21:26:43 bouyer Exp $ */
/* $NetBSD: ata_wdc.c,v 1.59 2004/08/01 21:40:41 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer.
@ -66,7 +66,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.58 2004/07/31 21:26:43 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: ata_wdc.c,v 1.59 2004/08/01 21:40:41 bouyer Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@ -133,7 +133,7 @@ static void wdc_ata_kill_pending(struct ata_drive_datas *);
const struct ata_bustype wdc_ata_bustype = {
SCSIPI_BUSTYPE_ATA,
wdc_ata_bio,
wdc_reset_channel,
wdc_reset_drive,
wdc_exec_command,
ata_get_params,
wdc_ata_addref,

View File

@ -1,4 +1,4 @@
/* $NetBSD: atavar.h,v 1.44 2004/07/31 21:26:43 bouyer Exp $ */
/* $NetBSD: atavar.h,v 1.45 2004/08/01 21:40:41 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@ -81,6 +81,8 @@ struct ata_queue {
struct atabus_softc {
struct device sc_dev;
struct wdc_channel *sc_chan; /* XXXwdc */
int sc_flags;
#define ATABUSCF_OPEN 0x01
};
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdc.c,v 1.182 2004/07/31 21:26:42 bouyer Exp $ */
/* $NetBSD: wdc.c,v 1.183 2004/08/01 21:40:41 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved.
@ -70,7 +70,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.182 2004/07/31 21:26:42 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.183 2004/08/01 21:40:41 bouyer Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@ -146,7 +146,6 @@ const struct ata_bustype wdc_ata_bustype = {
static int wdcprobe1(struct wdc_channel*, int);
static void __wdcerror(struct wdc_channel*, char *);
static int __wdcwait_reset(struct wdc_channel *, int, int);
static void __wdc_reset_channel(struct wdc_channel *, int);
static void __wdccommand_done(struct wdc_channel *, struct ata_xfer *);
static void __wdccommand_done_end(struct wdc_channel *, struct ata_xfer *);
static void __wdccommand_kill_xfer(struct wdc_channel *,
@ -965,7 +964,7 @@ wdcintr(void *arg)
/* Put all disk in RESET state */
void
wdc_reset_channel(struct ata_drive_datas *drvp, int flags)
wdc_reset_drive(struct ata_drive_datas *drvp, int flags)
{
struct wdc_channel *chp = drvp->chnl_softc;
struct wdc_softc *wdc = chp->ch_wdc;
@ -974,13 +973,13 @@ wdc_reset_channel(struct ata_drive_datas *drvp, int flags)
DEBUG_FUNCS);
__wdc_reset_channel(chp, flags);
wdc_reset_channel(chp, flags);
}
static void
__wdc_reset_channel(struct wdc_channel *chp, int flags)
void
wdc_reset_channel(struct wdc_channel *chp, int flags)
{
struct ata_xfer *xfer;
struct ata_xfer *xfer, *next_xfer;
int drive;
/*
@ -994,15 +993,17 @@ __wdc_reset_channel(struct wdc_channel *chp, int flags)
if ((flags & AT_RST_NOCMD) == 0) {
xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer);
if (xfer && xfer->c_chp != chp)
__wdc_reset_channel(xfer->c_chp, flags);
wdc_reset_channel(xfer->c_chp, flags);
for (xfer = TAILQ_FIRST(&chp->ch_queue->queue_xfer);
xfer != 0; ) {
xfer != NULL; xfer = next_xfer) {
next_xfer = TAILQ_NEXT(xfer, c_xferchain);
if (xfer->c_chp != chp)
continue;
if ((flags & AT_RST_EMERG) == 0)
xfer->c_kill_xfer(chp, xfer, KILL_RESET);
}
}
chp->ch_flags &= ~(WDCF_IRQ_WAIT|WDCF_DMA_WAIT);
if ((flags & AT_POLL) == 0) {
if (chp->ch_flags & WDCF_TH_RESET) {
/* no need to schedule a reset more than one time */
@ -1012,7 +1013,11 @@ __wdc_reset_channel(struct wdc_channel *chp, int flags)
wakeup(&chp->ch_thread);
return;
}
(void) wdcreset(chp, RESET_POLL);
if ((flags & AT_WAIT) == 0) {
(void) wdcreset(chp, RESET_POLL);
} else {
(void) wdcreset(chp, RESET_SLEEP);
}
for (drive = 0; drive < 2; drive++) {
chp->ch_drive[drive].state = 0;
}
@ -1604,7 +1609,7 @@ wdc_downgrade_mode(struct ata_drive_datas *drvp, int flags)
wdc->set_modes(chp);
wdc_print_modes(chp);
/* reset the channel, which will shedule all drives for setup */
wdc_reset_channel(drvp, flags | AT_RST_NOCMD);
wdc_reset_channel(chp, flags | AT_RST_NOCMD);
return 1;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: wdcvar.h,v 1.57 2004/05/25 20:42:41 thorpej Exp $ */
/* $NetBSD: wdcvar.h,v 1.58 2004/08/01 21:40:41 bouyer Exp $ */
/*-
* Copyright (c) 1998, 2003 The NetBSD Foundation, Inc.
@ -209,7 +209,8 @@ void wdccommandext(struct wdc_channel *, u_int8_t, u_int8_t, u_int64_t,
u_int16_t);
void wdccommandshort(struct wdc_channel *, int, int);
void wdctimeout(void *arg);
void wdc_reset_channel(struct ata_drive_datas *, int);
void wdc_reset_drive(struct ata_drive_datas *, int);
void wdc_reset_channel(struct wdc_channel *, int);
int wdc_exec_command(struct ata_drive_datas *, struct wdc_command*);
#define WDC_COMPLETE 0x01

View File

@ -1,4 +1,4 @@
/* $NetBSD: atapi_wdc.c,v 1.71 2004/07/31 21:26:43 bouyer Exp $ */
/* $NetBSD: atapi_wdc.c,v 1.72 2004/08/01 21:40:41 bouyer Exp $ */
/*
* Copyright (c) 1998, 2001 Manuel Bouyer.
@ -30,7 +30,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.71 2004/07/31 21:26:43 bouyer Exp $");
__KERNEL_RCSID(0, "$NetBSD: atapi_wdc.c,v 1.72 2004/08/01 21:40:41 bouyer Exp $");
#ifndef WDCDEBUG
#define WDCDEBUG
@ -175,10 +175,10 @@ wdc_atapi_kill_xfer(struct wdc_channel *chp, struct ata_xfer *xfer, int reason)
callout_stop(&chp->ch_callout);
/* remove this command from xfer queue */
wdc_free_xfer(chp, xfer);
switch (reason) {
case KILL_GONE:
sc_xfer->error = XS_DRIVER_STUFFUP;
wdc_free_xfer(chp, xfer);
scsipi_done(sc_xfer);
break;
case KILL_RESET:

View File

@ -1,4 +1,4 @@
/* $NetBSD: ataio.h,v 1.3 2002/09/29 23:24:00 wiz Exp $ */
/* $NetBSD: ataio.h,v 1.4 2004/08/01 21:40:41 bouyer Exp $ */
#ifndef _SYS_ATAIO_H_
#define _SYS_ATAIO_H_
@ -35,4 +35,21 @@ typedef struct atareq {
#define ATAIOCCOMMAND _IOWR('Q', 8, atareq_t)
/*
* ATA bus IOCTL
*/
/* Scan bus for new devices. */
struct atabusioscan_args {
int at_dev; /* device to scan, -1 for wildcard */
};
#define ATABUSIOSCAN _IOW('A', 0, struct atabusioscan_args)
#define ATABUSIORESET _IO('A', 1) /* reset ATA bus */
struct atabusiodetach_args {
int at_dev; /* device to detach; -1 for wildcard */
};
#define ATABUSIODETACH _IOW('A', 2, struct atabusiodetach_args)
#endif /* _SYS_ATAIO_H_ */