diff --git a/sys/conf/majors b/sys/conf/majors index 78bd37dfcb50..02d11d164520 100644 --- a/sys/conf/majors +++ b/sys/conf/majors @@ -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 diff --git a/sys/dev/ata/ata.c b/sys/dev/ata/ata.c index ad920b533f73..42c27503c586 100644 --- a/sys/dev/ata/ata.c +++ b/sys/dev/ata/ata.c @@ -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 -__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 #include #include +#include +#include #include #include #include +#include #include #include @@ -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); +}; diff --git a/sys/dev/ata/ata_wdc.c b/sys/dev/ata/ata_wdc.c index 02da34e06e50..ca7008e9422c 100644 --- a/sys/dev/ata/ata_wdc.c +++ b/sys/dev/ata/ata_wdc.c @@ -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 -__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, diff --git a/sys/dev/ata/atavar.h b/sys/dev/ata/atavar.h index 0844268b6525..9e3c1aff5ef7 100644 --- a/sys/dev/ata/atavar.h +++ b/sys/dev/ata/atavar.h @@ -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 }; /* diff --git a/sys/dev/ic/wdc.c b/sys/dev/ic/wdc.c index 57acd6b010db..965001347d69 100644 --- a/sys/dev/ic/wdc.c +++ b/sys/dev/ic/wdc.c @@ -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 -__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; } diff --git a/sys/dev/ic/wdcvar.h b/sys/dev/ic/wdcvar.h index 937e76df206b..25b1c26d7016 100644 --- a/sys/dev/ic/wdcvar.h +++ b/sys/dev/ic/wdcvar.h @@ -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 diff --git a/sys/dev/scsipi/atapi_wdc.c b/sys/dev/scsipi/atapi_wdc.c index c3a5b8512b81..16caf3d55379 100644 --- a/sys/dev/scsipi/atapi_wdc.c +++ b/sys/dev/scsipi/atapi_wdc.c @@ -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 -__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: diff --git a/sys/sys/ataio.h b/sys/sys/ataio.h index 7ea953dd3fba..83cac4182dd8 100644 --- a/sys/sys/ataio.h +++ b/sys/sys/ataio.h @@ -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_ */