Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/sys/dev/ic/wdc.c,v rcsdiff: /ftp/cvs/cvsroot/src/sys/dev/ic/wdc.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.288 retrieving revision 1.288.4.4 diff -u -p -r1.288 -r1.288.4.4 --- src/sys/dev/ic/wdc.c 2017/10/20 07:06:07 1.288 +++ src/sys/dev/ic/wdc.c 2020/04/21 18:42:16 1.288.4.4 @@ -1,4 +1,4 @@ -/* $NetBSD: wdc.c,v 1.288 2017/10/20 07:06:07 jdolecek Exp $ */ +/* $NetBSD: wdc.c,v 1.288.4.4 2020/04/21 18:42:16 martin Exp $ */ /* * Copyright (c) 1998, 2001, 2003 Manuel Bouyer. All rights reserved. @@ -58,7 +58,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.288 2017/10/20 07:06:07 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wdc.c,v 1.288.4.4 2020/04/21 18:42:16 martin Exp $"); #include "opt_ata.h" #include "opt_wdc.h" @@ -126,15 +126,16 @@ extern const struct ata_bustype wdc_ata_ #else /* A fake one, the autoconfig will print "wd at foo ... not configured */ const struct ata_bustype wdc_ata_bustype = { - SCSIPI_BUSTYPE_ATA, - NULL, /* wdc_ata_bio */ - NULL, /* wdc_reset_drive */ - wdc_reset_channel, - wdc_exec_command, - NULL, /* ata_get_params */ - NULL, /* wdc_ata_addref */ - NULL, /* wdc_ata_delref */ - NULL /* ata_kill_pending */ + .bustype_type = SCSIPI_BUSTYPE_ATA, + .ata_bio = NULL, + .ata_reset_drive = NULL, + .ata_reset_channel = wdc_reset_channel, + .ata_exec_command = wdc_exec_command, + .ata_get_params = NULL, + .ata_addref = NULL, + .ata_delref = NULL, + .ata_killpending = NULL, + .ata_recovery = NULL, }; #endif @@ -202,6 +203,7 @@ wdc_allocate_regs(struct wdc_softc *wdc) void wdc_sataprobe(struct ata_channel *chp) { + struct wdc_softc *wdc = CHAN_TO_WDC(chp); struct wdc_regs *wdr = CHAN_TO_WDC_REGS(chp); uint8_t st = 0, sc __unused, sn __unused, cl, ch; int i; @@ -242,7 +244,7 @@ wdc_sataprobe(struct ata_channel *chp) "cl=0x%x ch=0x%x\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, sc, sn, cl, ch), DEBUG_PROBE); - if (atabus_alloc_drives(chp, 1) != 0) + if (atabus_alloc_drives(chp, wdc->wdc_maxdrives) != 0) return; /* * sc and sn are supposed to be 0x1 for ATAPI, but in some @@ -294,15 +296,18 @@ wdc_drvprobe(struct ata_channel *chp) u_int8_t st0 = 0, st1 = 0; int i, j, error, tfd; - if (atabus_alloc_drives(chp, wdc->wdc_maxdrives) != 0) + ata_channel_lock(chp); + if (atabus_alloc_drives(chp, wdc->wdc_maxdrives) != 0) { + ata_channel_unlock(chp); return; + } if (wdcprobe1(chp, 0) == 0) { /* No drives, abort the attach here. */ atabus_free_drives(chp); + ata_channel_unlock(chp); return; } - ata_channel_lock(chp); /* for ATA/OLD drives, wait for DRDY, 3s timeout */ for (i = 0; i < mstohz(3000); i++) { /* @@ -476,6 +481,14 @@ wdc_drvprobe(struct ata_channel *chp) int wdcprobe(struct wdc_regs *wdr) { + + return wdcprobe_with_reset(wdr, NULL); +} + +int +wdcprobe_with_reset(struct wdc_regs *wdr, + void (*do_reset)(struct ata_channel *, int)) +{ struct wdc_softc wdc; struct ata_channel ch; int rv; @@ -486,11 +499,12 @@ wdcprobe(struct wdc_regs *wdr) ch.ch_atac = &wdc.sc_atac; wdc.regs = wdr; - /* default reset method */ - if (wdc.reset == NULL) - wdc.reset = wdc_do_reset; + /* check the MD reset method */ + wdc.reset = (do_reset != NULL) ? do_reset : wdc_do_reset; + ata_channel_lock(&ch); rv = wdcprobe1(&ch, 1); + ata_channel_unlock(&ch); ata_channel_destroy(&ch); @@ -514,7 +528,6 @@ wdcprobe1(struct ata_channel *chp, int p * Sanity check to see if the wdc channel responds at all. */ - ata_channel_lock(chp); if ((wdc->cap & WDC_CAPABILITY_NO_EXTRA_RESETS) == 0) { while (wdc_probe_count-- > 0) { if (wdc->select) @@ -667,7 +680,6 @@ wdcprobe1(struct ata_channel *chp, int p } if (ret_value == 0) { - ata_channel_unlock(chp); return 0; } } @@ -715,7 +727,6 @@ wdcprobe1(struct ata_channel *chp, int p /* if reset failed, there's nothing here */ if (ret_value == 0) { - ata_channel_unlock(chp); return 0; } @@ -768,7 +779,6 @@ wdcprobe1(struct ata_channel *chp, int p (void)bus_space_read_1(wdr->cmd_iot, wdr->cmd_iohs[wd_status], 0); } - ata_channel_unlock(chp); return (ret_value); } @@ -919,8 +929,8 @@ ignore: } #endif chp->ch_flags &= ~ATACH_IRQ_WAIT; - KASSERT(xfer->c_intr != NULL); - ret = xfer->c_intr(chp, xfer, 1); + KASSERT(xfer->ops != NULL && xfer->ops->c_intr != NULL); + ret = xfer->ops->c_intr(chp, xfer, 1); if (ret == 0) /* irq was not for us, still waiting for irq */ chp->ch_flags |= ATACH_IRQ_WAIT; return (ret); @@ -932,19 +942,24 @@ wdc_reset_drive(struct ata_drive_datas * { struct ata_channel *chp = drvp->chnl_softc; + ata_channel_lock_owned(chp); + KASSERT(sigp == NULL); ATADEBUG_PRINT(("wdc_reset_drive %s:%d for drive %d\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, drvp->drive), DEBUG_FUNCS); - ata_reset_channel(chp, flags); + ata_thread_run(chp, flags, ATACH_TH_RESET, ATACH_NODRIVE); } void wdc_reset_channel(struct ata_channel *chp, int flags) { struct ata_xfer *xfer; + + ata_channel_lock_owned(chp); + #if NATA_DMA || NATA_PIOBM struct wdc_softc *wdc = CHAN_TO_WDC(chp); #endif @@ -955,9 +970,7 @@ wdc_reset_channel(struct ata_channel *ch * if the current command is on an ATAPI device, issue a * ATAPI_SOFT_RESET */ - xfer = ata_queue_get_active_xfer(chp); - - ata_channel_lock(chp); + xfer = ata_queue_get_active_xfer_locked(chp); if (xfer && xfer->c_chp == chp && (xfer->c_flags & C_ATAPI)) { wdccommandshort(chp, xfer->c_drive, ATAPI_SOFT_RESET); @@ -984,9 +997,8 @@ wdc_reset_channel(struct ata_channel *ch */ if (xfer) { if (xfer->c_chp != chp) { - ata_channel_unlock(chp); - ata_reset_channel(xfer->c_chp, flags); - ata_channel_lock(chp); + ata_thread_run(xfer->c_chp, flags, ATACH_TH_RESET, + ATACH_NODRIVE); } else { #if NATA_DMA || NATA_PIOBM /* @@ -1004,8 +1016,6 @@ wdc_reset_channel(struct ata_channel *ch } ata_kill_active(chp, KILL_RESET, flags); - - ata_channel_unlock(chp); } static int @@ -1231,7 +1241,7 @@ __wdcwait(struct ata_channel *chp, int m if (!cold && xtime > WDCNDELAY_DEBUG) { struct ata_xfer *xfer; - xfer = ata_queue_get_active_xfer(chp); + xfer = ata_queue_get_active_xfer_locked(chp); if (xfer == NULL) printf("%s channel %d: warning: busy-wait took %dus\n", device_xname(chp->ch_atac->atac_dev), @@ -1268,8 +1278,7 @@ wdcwait(struct ata_channel *chp, int mas else { error = __wdcwait(chp, mask, bits, WDCDELAY_POLL, tfd); if (error != 0) { - if ((chp->ch_flags & ATACH_TH_RUN) || - (flags & AT_WAIT)) { + if (ata_is_thread_run(chp) || (flags & AT_WAIT)) { /* * we're running in the channel thread * or some userland thread context @@ -1324,8 +1333,8 @@ wdc_dmawait(struct ata_channel *chp, str void wdctimeout(void *arg) { - struct ata_xfer *xfer = arg; - struct ata_channel *chp = xfer->c_chp; + struct ata_xfer *xfer; + struct ata_channel *chp = arg; #if NATA_DMA || NATA_PIOBM struct wdc_softc *wdc = CHAN_TO_WDC(chp); #endif @@ -1334,6 +1343,10 @@ wdctimeout(void *arg) ATADEBUG_PRINT(("wdctimeout\n"), DEBUG_FUNCS); s = splbio(); + + callout_ack(&chp->c_timo_callout); + + xfer = ata_queue_get_active_xfer(chp); KASSERT(xfer != NULL); if (ata_timo_xfer_check(xfer)) { @@ -1361,21 +1374,28 @@ wdctimeout(void *arg) * in case it will miss another irq while in this transfer * We arbitray chose it to be 1s */ - callout_reset(&xfer->c_timo_callout, hz, wdctimeout, xfer); + callout_reset(&chp->c_timo_callout, hz, wdctimeout, chp); xfer->c_flags |= C_TIMEOU; - KASSERT(xfer->c_intr != NULL); - xfer->c_intr(chp, xfer, 1); + KASSERT(xfer->ops != NULL && xfer->ops->c_intr != NULL); + xfer->ops->c_intr(chp, xfer, 1); out: splx(s); } -int +static const struct ata_xfer_ops wdc_cmd_xfer_ops = { + .c_start = __wdccommand_start, + .c_poll = __wdccommand_poll, + .c_abort = __wdccommand_done, + .c_intr = __wdccommand_intr, + .c_kill_xfer = __wdccommand_kill_xfer, +}; + +void wdc_exec_command(struct ata_drive_datas *drvp, struct ata_xfer *xfer) { struct ata_channel *chp = drvp->chnl_softc; struct ata_command *ata_c = &xfer->c_ata_c; - int s, ret; ATADEBUG_PRINT(("wdc_exec_command %s:%d:%d\n", device_xname(chp->ch_atac->atac_dev), chp->ch_channel, @@ -1391,36 +1411,9 @@ wdc_exec_command(struct ata_drive_datas xfer->c_drive = drvp->drive; xfer->c_databuf = ata_c->data; xfer->c_bcount = ata_c->bcount; - xfer->c_start = __wdccommand_start; - xfer->c_poll = __wdccommand_poll; - xfer->c_abort = __wdccommand_done; - xfer->c_intr = __wdccommand_intr; - xfer->c_kill_xfer = __wdccommand_kill_xfer; + xfer->ops = &wdc_cmd_xfer_ops; - s = splbio(); ata_exec_xfer(chp, xfer); -#ifdef DIAGNOSTIC - if ((ata_c->flags & AT_POLL) != 0 && - (ata_c->flags & AT_DONE) == 0) - panic("wdc_exec_command: polled command not done"); -#endif - if (ata_c->flags & AT_DONE) { - ret = ATACMD_COMPLETE; - } else { - if (ata_c->flags & AT_WAIT) { - ata_channel_lock(chp); - if ((ata_c->flags & AT_DONE) == 0) { - ata_wait_xfer(chp, xfer); - KASSERT((ata_c->flags & AT_DONE) != 0); - } - ata_channel_unlock(chp); - ret = ATACMD_COMPLETE; - } else { - ret = ATACMD_QUEUED; - } - } - splx(s); - return ret; } static int @@ -1474,8 +1467,8 @@ __wdccommand_start(struct ata_channel *c if ((ata_c->flags & AT_POLL) == 0) { chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */ - callout_reset(&xfer->c_timo_callout, ata_c->timeout / 1000 * hz, - wdctimeout, xfer); + callout_reset(&chp->c_timo_callout, ata_c->timeout / 1000 * hz, + wdctimeout, chp); return ATASTART_STARTED; } @@ -1516,7 +1509,7 @@ __wdccommand_intr(struct ata_channel *ch chp->ch_drive[xfer->c_drive].drive_flags; } else { /* - * Other data structure are opaque and should be transfered + * Other data structure are opaque and should be transferred * as is. */ drive_flags = chp->ch_drive[xfer->c_drive].drive_flags; @@ -1597,8 +1590,8 @@ again: ata_c->flags |= AT_XFDONE; if ((ata_c->flags & AT_POLL) == 0) { chp->ch_flags |= ATACH_IRQ_WAIT; /* wait for interrupt */ - callout_reset(&xfer->c_timo_callout, - mstohz(ata_c->timeout), wdctimeout, xfer); + callout_reset(&chp->c_timo_callout, + mstohz(ata_c->timeout), wdctimeout, chp); ata_channel_unlock(chp); return 1; } else { @@ -1691,10 +1684,10 @@ __wdccommand_done(struct ata_channel *ch ata_c->r_device &= 0xf0; } - ata_deactivate_xfer(chp, xfer); - __wdccommand_done_end(chp, xfer); + ata_deactivate_xfer(chp, xfer); + out: if (ata_c->flags & AT_POLL) { /* enable interrupts */ @@ -1713,11 +1706,7 @@ __wdccommand_done_end(struct ata_channel { struct ata_command *ata_c = &xfer->c_ata_c; - ata_channel_lock(chp); ata_c->flags |= AT_DONE; - if (ata_c->flags & AT_WAIT) - ata_wake_xfer(chp, xfer); - ata_channel_unlock(chp); } static void @@ -1743,10 +1732,10 @@ __wdccommand_kill_xfer(struct ata_channe panic("__wdccommand_kill_xfer"); } + __wdccommand_done_end(chp, xfer); + if (deactivate) ata_deactivate_xfer(chp, xfer); - - __wdccommand_done_end(chp, xfer); } /*