Module Name: src Committed By: jdolecek Date: Mon Apr 24 09:57:22 UTC 2017
Modified Files: src/sys/dev/ata [jdolecek-ncq]: wd.c Log Message: sync with HEAD, remove the nonfunctional Seagate 'mod15write' bug workaround To generate a diff of this commit: cvs rdiff -u -r1.428.2.11 -r1.428.2.12 src/sys/dev/ata/wd.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/ata/wd.c diff -u src/sys/dev/ata/wd.c:1.428.2.11 src/sys/dev/ata/wd.c:1.428.2.12 --- src/sys/dev/ata/wd.c:1.428.2.11 Sun Apr 23 01:21:04 2017 +++ src/sys/dev/ata/wd.c Mon Apr 24 09:57:22 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: wd.c,v 1.428.2.11 2017/04/23 01:21:04 jakllsch Exp $ */ +/* $NetBSD: wd.c,v 1.428.2.12 2017/04/24 09:57:22 jdolecek Exp $ */ /* * Copyright (c) 1998, 2001 Manuel Bouyer. All rights reserved. @@ -54,7 +54,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.11 2017/04/23 01:21:04 jakllsch Exp $"); +__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.12 2017/04/24 09:57:22 jdolecek Exp $"); #include "opt_ata.h" @@ -186,11 +186,6 @@ void wi_free(struct wd_ioctl *); struct wd_ioctl *wi_get(struct wd_softc *); void wdioctlstrategy(struct buf *); -struct wd_split_mod15_private { - struct buf *bp; - struct ata_xfer *xfer; -}; - void wdgetdefaultlabel(struct wd_softc *, struct disklabel *); void wdgetdisklabel(struct wd_softc *); void wdstart(struct wd_softc *); @@ -349,6 +344,10 @@ wdattach(device_t parent, device_t self, char sbuf[sizeof(WD_QUIRK_FMT) + 64]; snprintb(sbuf, sizeof(sbuf), WD_QUIRK_FMT, wd->sc_quirks); aprint_normal_dev(self, "quirks %s\n", sbuf); + + if (wd->sc_quirks & WD_QUIRK_SPLIT_MOD15_WRITE) { + aprint_error_dev(self, "drive corrupts write transfers with certain controllers, consider replacing\n"); + } } if ((wd->sc_params.atap_multi & 0xff) > 1) { @@ -657,123 +656,12 @@ wdstart(struct wd_softc *wd) mutex_exit(&wd->sc_lock); } -static void -wd_split_mod15_write(struct buf *bp) -{ - struct wd_split_mod15_private *m = bp->b_private; - struct buf *obp = m->bp; - struct ata_xfer *xfer = m->xfer; - struct wd_softc *wd = - device_lookup_private(&wd_cd, DISKUNIT(obp->b_dev)); - - free(m, sizeof *m); - - mutex_enter(&wd->sc_lock); - if (__predict_false(bp->b_error != 0)) { - /* - * Propagate the error. If this was the first half of - * the original transfer, make sure to account for that - * in the residual. - */ - if (bp->b_data == obp->b_data) - bp->b_resid += bp->b_bcount; - goto done; - } - - /* - * If this was the second half of the transfer, we're all done! - */ - if (bp->b_data != obp->b_data) - goto done; - - /* - * Advance the pointer to the second half and issue that command - * using the same xfer. - */ - bp->b_flags = obp->b_flags; - bp->b_oflags = obp->b_oflags; - bp->b_cflags = obp->b_cflags; - bp->b_data = (char *)bp->b_data + bp->b_bcount; - bp->b_blkno += (bp->b_bcount / DEV_BSIZE); - bp->b_rawblkno += (bp->b_bcount / wd->sc_blksize); - memset(xfer, 0, sizeof(*xfer)); - wdstart1(wd, bp, xfer); - mutex_exit(&wd->sc_lock); - return; - - done: - obp->b_error = bp->b_error; - obp->b_resid = bp->b_resid; - mutex_exit(&wd->sc_lock); - - putiobuf(bp); - biodone(obp); - /* wddone() will call wdstart() */ -} - void wdstart1(struct wd_softc *wd, struct buf *bp, struct ata_xfer *xfer) { /* must be locked on entry */ KASSERT(mutex_owned(&wd->sc_lock)); - /* - * Deal with the "split mod15 write" quirk. We just divide the - * transfer in two, doing the first half and then then second half - * with the same command opening. - * - * Note we MUST do this here, because we can't let insertion - * into the bufq cause the transfers to be re-merged. - */ - if (__predict_false((wd->sc_quirks & WD_QUIRK_SPLIT_MOD15_WRITE) != 0 && - (bp->b_flags & B_READ) == 0 && - bp->b_bcount > 512 && - ((bp->b_bcount / 512) % 15) == 1)) { - struct buf *nbp; - struct wd_split_mod15_private *m; - - m = malloc(sizeof *m, M_TEMP, M_NOWAIT); - if (m == NULL) - goto fail; - - nbp = getiobuf(NULL, false); - if (__predict_false(nbp == NULL)) { - free(m, sizeof *m); -fail: - /* No memory -- fail the iop. */ - bp->b_error = ENOMEM; - bp->b_resid = bp->b_bcount; - biodone(bp); - ata_free_xfer(wd->drvp->chnl_softc, xfer); - return; - } - - nbp->b_error = 0; - nbp->b_proc = bp->b_proc; - nbp->b_dev = bp->b_dev; - - nbp->b_bcount = bp->b_bcount / 2; - nbp->b_bufsize = bp->b_bcount / 2; - nbp->b_data = bp->b_data; - - nbp->b_blkno = bp->b_blkno; - nbp->b_rawblkno = bp->b_rawblkno; - - nbp->b_flags = bp->b_flags; - nbp->b_oflags = bp->b_oflags; - nbp->b_cflags = bp->b_cflags; - nbp->b_iodone = wd_split_mod15_write; - - /* Put ptr to orig buf in b_private and use new buf */ - m->bp = bp; - m->xfer = xfer; - nbp->b_private = m; - - BIO_COPYPRIO(nbp, bp); - - bp = nbp; - } - xfer->c_bio.blkno = bp->b_rawblkno; xfer->c_bio.bcount = bp->b_bcount; xfer->c_bio.databuf = bp->b_data; @@ -835,7 +723,7 @@ wddone(void *v, struct ata_xfer *xfer) { struct wd_softc *wd = device_private(v); const char *errmsg; - int do_perror = 0, finish; + int do_perror = 0; struct buf *bp; ATADEBUG_PRINT(("wddone %s\n", device_xname(wd->sc_dev)), @@ -938,21 +826,10 @@ noerror: if ((xfer->c_bio.flags & ATA_CO disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid), (bp->b_flags & B_READ)); rnd_add_uint32(&wd->rnd_source, bp->b_blkno); - - /* - * XXX Yuck, but we don't want to free the xfer in this case. - * See wd_split_mod15_write() for details. - */ - finish = (bp->b_iodone != wd_split_mod15_write); - mutex_exit(&wd->sc_lock); - biodone(bp); - - if (__predict_true(finish)) { - ata_free_xfer(wd->drvp->chnl_softc, xfer); - wdstart(wd); - } + ata_free_xfer(wd->drvp->chnl_softc, xfer); + wdstart(wd); } void