diff options
author | Marco Peereboom <marco@cvs.openbsd.org> | 2009-11-05 03:33:53 +0000 |
---|---|---|
committer | Marco Peereboom <marco@cvs.openbsd.org> | 2009-11-05 03:33:53 +0000 |
commit | da070d530c1c6b123eb24e34db48251ca1f04d52 (patch) | |
tree | 1addc34954610ed621a1311d459df0758d2a0a2c /sys | |
parent | 57a5a2863daad723dd081b62ec1c6888f5435bfe (diff) |
The big diff dlg committed to the midlayer breaks NO_CCB and
TRY_AGAIN_LATER. NO_CCB is a timer based mechanism that can trivially
be made to fail by running IO to two or more disks simultaneously. The
TRY_AGAIN_LATER thing is more subtle because it now is a permanent
failure instead of transient however this is much harder to hit because
something must have gone wrong before it hits.
ok deraadt krw miod
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/ic/mpi.c | 4 | ||||
-rw-r--r-- | sys/scsi/mpath.c | 97 | ||||
-rw-r--r-- | sys/scsi/scsi_base.c | 466 | ||||
-rw-r--r-- | sys/scsi/scsi_ioctl.c | 301 | ||||
-rw-r--r-- | sys/scsi/scsiconf.c | 228 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 49 | ||||
-rw-r--r-- | sys/scsi/sd.c | 440 | ||||
-rw-r--r-- | sys/scsi/sdvar.h | 14 |
8 files changed, 904 insertions, 695 deletions
diff --git a/sys/dev/ic/mpi.c b/sys/dev/ic/mpi.c index d0768a8115f..2a9069c05b0 100644 --- a/sys/dev/ic/mpi.c +++ b/sys/dev/ic/mpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpi.c,v 1.117 2009/11/02 23:20:41 marco Exp $ */ +/* $OpenBSD: mpi.c,v 1.118 2009/11/05 03:33:52 marco Exp $ */ /* * Copyright (c) 2005, 2006 David Gwynne <dlg@openbsd.org> @@ -2176,6 +2176,7 @@ mpi_eventnotify_done(struct mpi_ccb *ccb) void mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb) { +#if 0 struct mpi_evt_sas_change *ch; u_int8_t *data; @@ -2213,6 +2214,7 @@ mpi_evt_sas(struct mpi_softc *sc, struct mpi_rcb *rcb) "0x%02x\n", DEVNAME(sc), ch->reason); break; } +#endif } void diff --git a/sys/scsi/mpath.c b/sys/scsi/mpath.c index 7f0a4f64766..498817acd59 100644 --- a/sys/scsi/mpath.c +++ b/sys/scsi/mpath.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpath.c,v 1.7 2009/10/23 01:02:29 dlg Exp $ */ +/* $OpenBSD: mpath.c,v 1.8 2009/11/05 03:33:52 marco Exp $ */ /* * Copyright (c) 2009 David Gwynne <dlg@openbsd.org> @@ -47,7 +47,7 @@ struct mpath_path { TAILQ_HEAD(mpath_paths, mpath_path); struct mpath_node { - struct devid *node_id; + struct devid node_id; struct mpath_paths node_paths; }; @@ -78,8 +78,6 @@ int mpath_cmd(struct scsi_xfer *); void mpath_minphys(struct buf *, struct scsi_link *); int mpath_probe(struct scsi_link *); -void mpath_done(struct scsi_xfer *); - struct scsi_adapter mpath_switch = { mpath_cmd, scsi_minphys, @@ -138,13 +136,9 @@ mpath_xs_stuffup(struct scsi_xfer *xs) int mpath_probe(struct scsi_link *link) { - struct mpath_node *n = mpath_nodes[link->target]; - - if (link->lun != 0 || n == NULL) + if (link->lun != 0 || mpath_nodes[link->target] == NULL) return (ENXIO); - link->id = devid_copy(n->node_id); - return (0); } @@ -154,53 +148,36 @@ mpath_cmd(struct scsi_xfer *xs) struct scsi_link *link = xs->sc_link; struct mpath_node *n = mpath_nodes[link->target]; struct mpath_path *p = TAILQ_FIRST(&n->node_paths); - struct scsi_xfer *mxs; + int rv; + int s; if (n == NULL || p == NULL) { mpath_xs_stuffup(xs); return (COMPLETE); } - mxs = scsi_xs_get(p->path_link, xs->flags); - if (mxs == NULL) { - mpath_xs_stuffup(xs); - return (COMPLETE); - } - - memcpy(mxs->cmd, xs->cmd, xs->cmdlen); - mxs->cmdlen = xs->cmdlen; - mxs->data = xs->data; - mxs->datalen = xs->datalen; - mxs->retries = xs->retries; - mxs->timeout = xs->timeout; - mxs->req_sense_length = xs->req_sense_length; - - mxs->cookie = xs; - mxs->done = mpath_done; - - scsi_xs_exec(mxs); - - return (COMPLETE); /* doesnt matter anymore */ -} - -void -mpath_done(struct scsi_xfer *mxs) -{ - struct scsi_xfer *xs = mxs->cookie; - int s; - - xs->error = mxs->error; - xs->status = mxs->status; - xs->flags = mxs->flags; - xs->resid = mxs->resid; + rv = scsi_scsi_cmd(p->path_link, xs->cmd, xs->cmdlen, + xs->data, xs->datalen, + 2, xs->timeout, NULL, SCSI_POLL | + (xs->flags & (SCSI_DATA_IN|SCSI_DATA_OUT))); - memcpy(&xs->sense, &mxs->sense, sizeof(xs->sense)); - scsi_xs_put(mxs); + xs->flags |= ITSDONE; + if (rv == 0) { + xs->error = XS_NOERROR; + xs->status = SCSI_OK; + xs->resid = 0; + } else { + printf("%s: t%dl%d rv %d cmd %x\n", DEVNAME(mpath), + link->target, link->lun, rv, xs->cmd->opcode); + xs->error = XS_DRIVER_STUFFUP; + } s = splbio(); scsi_done(xs); splx(s); + + return (COMPLETE); } void @@ -228,14 +205,14 @@ mpath_path_attach(struct scsi_link *link) return (ENODEV); /* XXX this is dumb. should check inq shizz */ - if (ISSET(link->flags, SDEV_VIRTUAL) || link->id == NULL) + if (link->id.d_type == DEVID_NONE) return (ENXIO); for (target = 0; target < MPATH_BUSWIDTH; target++) { if ((n = mpath_nodes[target]) == NULL) continue; - if (DEVID_CMP(n->node_id, link->id)) + if (DEVID_CMP(&n->node_id, &link->id)) break; n = NULL; @@ -252,18 +229,13 @@ mpath_path_attach(struct scsi_link *link) n = malloc(sizeof(*n), M_DEVBUF, M_WAITOK | M_ZERO); TAILQ_INIT(&n->node_paths); - n->node_id = devid_copy(link->id); + n->node_id.d_type = link->id.d_type; + n->node_id.d_len = link->id.d_len; + n->node_id.d_id = malloc(n->node_id.d_len, M_DEVBUF, M_DEVBUF); + memcpy(n->node_id.d_id, link->id.d_id, n->node_id.d_len); mpath_nodes[target] = n; probe = 1; - } else { - /* - * instead of carrying identical values in different devid - * instances, delete the new one and reference the old one in - * the new scsi_link. - */ - devid_free(link->id); - link->id = devid_copy(n->node_id); } p = malloc(sizeof(*p), M_DEVBUF, M_WAITOK); @@ -288,7 +260,7 @@ mpath_path_detach(struct scsi_link *link, int flags) if ((n = mpath_nodes[target]) == NULL) continue; - if (DEVID_CMP(n->node_id, link->id)) + if (DEVID_CMP(&n->node_id, &link->id)) break; n = NULL; @@ -307,16 +279,3 @@ mpath_path_detach(struct scsi_link *link, int flags) panic("mpath: unable to locate path for detach"); } - -void -mpath_path_activate(struct scsi_link *link) -{ - -} - -void -mpath_path_deactivate(struct scsi_link *link) -{ - -} - diff --git a/sys/scsi/scsi_base.c b/sys/scsi/scsi_base.c index fcaaffd144e..e5de94bd23e 100644 --- a/sys/scsi/scsi_base.c +++ b/sys/scsi/scsi_base.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_base.c,v 1.137 2009/10/27 11:38:24 dlg Exp $ */ +/* $OpenBSD: scsi_base.c,v 1.138 2009/11/05 03:33:52 marco Exp $ */ /* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */ /* @@ -50,14 +50,15 @@ #include <scsi/scsi_disk.h> #include <scsi/scsiconf.h> +static __inline struct scsi_xfer *scsi_make_xs(struct scsi_link *, + struct scsi_generic *, int cmdlen, u_char *data_addr, + int datalen, int retries, int timeout, struct buf *, int flags); static __inline void asc2ascii(u_int8_t, u_int8_t ascq, char *result, size_t len); int sc_err1(struct scsi_xfer *); int scsi_interpret_sense(struct scsi_xfer *); char *scsi_decode_sense(struct scsi_sense_data *, int); -void scsi_xs_done(struct scsi_xfer *); - /* Values for flag parameter to scsi_decode_sense. */ #define DECODE_SENSE_KEY 1 #define DECODE_ASC_ASCQ 2 @@ -94,7 +95,6 @@ scsi_init() /* Initialize the scsi_xfer pool. */ pool_init(&scsi_xfer_pool, sizeof(struct scsi_xfer), 0, 0, 0, "scxspl", NULL); - pool_setipl(&scsi_xfer_pool, IPL_BIO); /* Initialize the scsi_plug pool */ pool_init(&scsi_plug_pool, sizeof(struct scsi_plug), 0, 0, 0, "scsiplug", NULL); @@ -183,43 +183,42 @@ scsi_deinit() */ struct scsi_xfer * -scsi_xs_get(struct scsi_link *link, int flags) +scsi_get_xs(struct scsi_link *sc_link, int flags) { - struct scsi_xfer *xs; + struct scsi_xfer *xs; + int s; + + SC_DEBUG(sc_link, SDEV_DB3, ("scsi_get_xs\n")); - mtx_enter(&link->mtx); - while (link->openings == 0) { - if (ISSET(flags, SCSI_NOSLEEP)) { - mtx_leave(&link->mtx); + s = splbio(); + while (sc_link->openings == 0) { + SC_DEBUG(sc_link, SDEV_DB3, ("sleeping\n")); + if ((flags & SCSI_NOSLEEP) != 0) { + splx(s); + return (NULL); + } + sc_link->flags |= SDEV_WAITING; + if (tsleep(sc_link, PRIBIO|PCATCH, "getxs", 0)) { + /* Bail out on getting a signal. */ + sc_link->flags &= ~SDEV_WAITING; + splx(s); return (NULL); } - - SET(link->flags, SDEV_WAITING); - msleep(link, &link->mtx, PRIBIO, "getxs", 0); } - link->openings--; - mtx_leave(&link->mtx); - - /* pool is shared, link mtx is not */ + SC_DEBUG(sc_link, SDEV_DB3, ("calling pool_get\n")); xs = pool_get(&scsi_xfer_pool, - ISSET(flags, SCSI_NOSLEEP) ? PR_NOWAIT : PR_WAITOK); - if (xs == NULL) { - mtx_enter(&link->mtx); - link->openings++; - mtx_leave(&link->mtx); - } else { + ((flags & SCSI_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK)); + if (xs != NULL) { + bzero(xs, sizeof(*xs)); + sc_link->openings--; xs->flags = flags; - xs->sc_link = link; - xs->retries = SCSI_RETRIES; - xs->timeout = 0; - bzero(&xs->cmdstore, sizeof(xs->cmdstore)); - xs->cmd = &xs->cmdstore; - xs->cmdlen = 0; - xs->data = NULL; - xs->datalen = 0; - xs->resid = 0; - xs->bp = NULL; + } else { + sc_print_addr(sc_link); + printf("cannot allocate scsi xs\n"); } + splx(s); + + SC_DEBUG(sc_link, SDEV_DB3, ("returning\n")); return (xs); } @@ -230,21 +229,75 @@ scsi_xs_get(struct scsi_link *link, int flags) * If another process is waiting for an xs, do a wakeup, let it proceed */ void -scsi_xs_put(struct scsi_xfer *xs) +scsi_free_xs(struct scsi_xfer *xs, int start) { - struct scsi_link *link = xs->sc_link; + struct scsi_link *sc_link = xs->sc_link; - pool_put(&scsi_xfer_pool, xs); + splassert(IPL_BIO); + + SC_DEBUG(sc_link, SDEV_DB3, ("scsi_free_xs\n")); - mtx_enter(&link->mtx); - link->openings++; + pool_put(&scsi_xfer_pool, xs); + sc_link->openings++; /* If someone is waiting for scsi_xfer, wake them up. */ - if (ISSET(link->flags, SDEV_WAITING)) { - CLR(link->flags, SDEV_WAITING); - wakeup(link); + if ((sc_link->flags & SDEV_WAITING) != 0) { + sc_link->flags &= ~SDEV_WAITING; + wakeup(sc_link); + } else if (start && sc_link->device->start) { + SC_DEBUG(sc_link, SDEV_DB2, + ("calling private start()\n")); + (*(sc_link->device->start)) (sc_link->device_softc); } - mtx_leave(&link->mtx); +} + +/* + * Make a scsi_xfer, and return a pointer to it. + */ +static __inline struct scsi_xfer * +scsi_make_xs(struct scsi_link *sc_link, struct scsi_generic *scsi_cmd, + int cmdlen, u_char *data_addr, int datalen, int retries, int timeout, + struct buf *bp, int flags) +{ + struct scsi_xfer *xs; + + if ((xs = scsi_get_xs(sc_link, flags)) == NULL) + return (NULL); + + /* + * Fill out the scsi_xfer structure. We don't know whose context + * the cmd is in, so copy it. + */ + xs->sc_link = sc_link; + bcopy(scsi_cmd, &xs->cmdstore, cmdlen); + xs->cmd = &xs->cmdstore; + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->retries = retries; + xs->timeout = timeout; + xs->bp = bp; + + /* + * Set the LUN in the CDB if it fits in the three bits available. This + * may only be needed if we have an older device. However, we also set + * it for more modern SCSI devices "just in case". The old code + * assumed everything newer than SCSI-2 would not need it, but why risk + * it? This was the old conditional: + * + * if ((SCSISPC(sc_link->inqdata.version) <= 2)) + */ + xs->cmd->bytes[0] &= ~SCSI_CMD_LUN_MASK; + if (sc_link->lun < 8) + xs->cmd->bytes[0] |= ((sc_link->lun << SCSI_CMD_LUN_SHIFT) & + SCSI_CMD_LUN_MASK); + +#ifdef SCSIDEBUG + if ((sc_link->flags & SDEV_DB1) != 0) + show_scsi_xs(xs); +#endif /* SCSIDEBUG */ + + return (xs); } /* @@ -706,49 +759,181 @@ scsi_report_luns(struct scsi_link *sc_link, int selectreport, return (error); } +/* + * This routine is called by the scsi interrupt when the transfer is complete. + */ void -scsi_xs_exec(struct scsi_xfer *xs) +scsi_done(struct scsi_xfer *xs) { - int rv; - int s; + struct scsi_link *sc_link = xs->sc_link; + struct buf *bp; + int error; + + SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n")); + + splassert(IPL_BIO); + + xs->flags |= ITSDONE; + + /* + * If it's a user level request, bypass all usual completion processing, + * let the user work it out.. We take reponsibility for freeing the + * xs when the user returns (and restarting the device's queue). + */ + if ((xs->flags & SCSI_USER) != 0) { + SC_DEBUG(sc_link, SDEV_DB3, ("calling user done()\n")); + scsi_user_done(xs); /* to take a copy of the sense etc. */ + SC_DEBUG(sc_link, SDEV_DB3, ("returned from user done()\n")); + + scsi_free_xs(xs, 1); /* restarts queue too */ + SC_DEBUG(sc_link, SDEV_DB3, ("returning to adapter\n")); + return; + } + + if (!((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)) { + /* + * if it's a normal upper level request, then ask + * the upper level code to handle error checking + * rather than doing it here at interrupt time + */ + wakeup(xs); + return; + } + + /* + * Go and handle errors now. + * If it returns ERESTART then we should RETRY + */ +retry: + error = sc_err1(xs); + if (error == ERESTART) { + switch ((*(sc_link->adapter->scsi_cmd)) (xs)) { + case SUCCESSFULLY_QUEUED: + return; + + case TRY_AGAIN_LATER: + xs->error = XS_BUSY; + /* FALLTHROUGH */ + case COMPLETE: + goto retry; + } + } + + bp = xs->bp; + if (bp != NULL) { + if (error) { + bp->b_error = error; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + } else { + bp->b_error = 0; + bp->b_resid = xs->resid; + } + } + + if (sc_link->device->done) { + /* + * Tell the device the operation is actually complete. + * No more will happen with this xfer. This for + * notification of the upper-level driver only; they + * won't be returning any meaningful information to us. + */ + (*sc_link->device->done)(xs); + } + scsi_free_xs(xs, 1); + if (bp != NULL) + biodone(bp); +} + +int +scsi_execute_xs(struct scsi_xfer *xs) +{ + int error, flags, rslt, s; xs->flags &= ~ITSDONE; xs->error = XS_NOERROR; xs->resid = xs->datalen; xs->status = 0; - rv = xs->sc_link->adapter->scsi_cmd(xs); - switch (rv) { - case NO_CCB: - if (!ISSET(xs->flags, SCSI_POLL) && xs->retries-- > 0) { - timeout_set(&xs->stimeout, - (void (*)(void *))scsi_xs_exec, xs); - timeout_add(&xs->stimeout, 1); - break; - } - /* FALLTHROUGH */ - case TRY_AGAIN_LATER: - /* hahaha, sif... */ + /* + * Do the transfer. If we are polling we will return: + * COMPLETE, Was poll, and scsi_done has been called + * TRY_AGAIN_LATER, Adapter short resources, try again + * + * if under full steam (interrupts) it will return: + * SUCCESSFULLY_QUEUED, will do a wakeup when complete + * TRY_AGAIN_LATER, (as for polling) + * After the wakeup, we must still check if it succeeded + * + * If we have a SCSI_NOSLEEP (typically because we have a buf) + * we just return. All the error processing and the buffer + * code both expect us to return straight to them, so as soon + * as the command is queued, return. + */ + + /* + * We save the flags here because the xs structure may already + * be freed by scsi_done by the time adapter->scsi_cmd returns. + * + * scsi_done is responsible for freeing the xs if either + * (flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP + * -or- + * (flags & SCSI_USER) != 0 + * + * Note: SCSI_USER must always be called with SCSI_NOSLEEP + * and never with SCSI_POLL, so the second expression should be + * is equivalent to the first. + */ - xs->error = XS_DRIVER_STUFFUP; + flags = xs->flags; +#ifdef DIAGNOSTIC + if ((flags & (SCSI_USER | SCSI_NOSLEEP)) == SCSI_USER) + panic("scsi_execute_xs: USER without NOSLEEP"); + if ((flags & (SCSI_USER | SCSI_POLL)) == (SCSI_USER | SCSI_POLL)) + panic("scsi_execute_xs: USER with POLL"); +#endif +retry: + rslt = (*(xs->sc_link->adapter->scsi_cmd))(xs); + switch (rslt) { + case SUCCESSFULLY_QUEUED: + if ((flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP) + return (EJUSTRETURN); +#ifdef DIAGNOSTIC + if (flags & SCSI_NOSLEEP) + panic("scsi_execute_xs: NOSLEEP and POLL"); +#endif s = splbio(); - scsi_done(xs); + /* Since the xs is active we can't bail out on a signal. */ + while ((xs->flags & ITSDONE) == 0) + tsleep(xs, PRIBIO + 1, "scsicmd", 0); splx(s); - break; - } -} + /* FALLTHROUGH */ + case COMPLETE: /* Polling command completed ok */ + if ((flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP) + return (EJUSTRETURN); + if (xs->bp) + return (EJUSTRETURN); + doit: + SC_DEBUG(xs->sc_link, SDEV_DB3, ("back in cmd()\n")); + if ((error = sc_err1(xs)) != ERESTART) + return (error); + goto retry; + + case TRY_AGAIN_LATER: /* adapter resource shortage */ + xs->error = XS_BUSY; + goto doit; -/* - * This routine is called by the adapter when its xs handling is done. - */ -void -scsi_done(struct scsi_xfer *xs) -{ - splassert(IPL_BIO); + case NO_CCB: + return (EAGAIN); - xs->flags |= ITSDONE; + default: + panic("scsi_execute_xs: invalid return code (%#x)", rslt); + } - xs->done(xs); +#ifdef DIAGNOSTIC + panic("scsi_execute_xs: impossible"); +#endif + return (EINVAL); } /* @@ -758,81 +943,54 @@ scsi_done(struct scsi_xfer *xs) * to associate with the transfer, we need that too. */ int -scsi_scsi_cmd(struct scsi_link *link, struct scsi_generic *scsi_cmd, +scsi_scsi_cmd(struct scsi_link *sc_link, struct scsi_generic *scsi_cmd, int cmdlen, u_char *data_addr, int datalen, int retries, int timeout, struct buf *bp, int flags) { - struct scsi_xfer *xs; - int error; - int s; + struct scsi_xfer *xs; + int error; + int s; + + SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n")); #ifdef DIAGNOSTIC if (bp != NULL && (flags & SCSI_NOSLEEP) == 0) panic("scsi_scsi_cmd: buffer without nosleep"); #endif - xs = scsi_xs_get(link, flags); - if (xs == NULL) + if ((xs = scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen, + retries, timeout, bp, flags)) == NULL) return (ENOMEM); - memcpy(xs->cmd, scsi_cmd, cmdlen); - xs->cmdlen = cmdlen; - xs->data = data_addr; - xs->datalen = datalen; - xs->retries = retries; - xs->timeout = timeout; - - xs->done = scsi_xs_done; +#ifdef SCSIDEBUG + if ((sc_link->flags & SDEV_DB1) != 0) + if (xs->datalen && (xs->flags & SCSI_DATA_OUT)) + show_mem(xs->data, min(64, xs->datalen)); +#endif /* SCSIDEBUG */ - do { - scsi_xs_exec(xs); - if (!ISSET(xs->flags, SCSI_POLL)) { - s = splbio(); - while (!ISSET(xs->flags, ITSDONE)) - tsleep(xs, PRIBIO, "scsicmd", 0); - splx(s); - } + error = scsi_execute_xs(xs); - error = sc_err1(xs); - } while (error == ERESTART); +#ifdef SCSIDEBUG + if ((sc_link->flags & SDEV_DB1) != 0) + if (xs->datalen && (xs->flags & SCSI_DATA_IN)) + show_mem(xs->data, min(64, xs->datalen)); +#endif /* SCSIDEBUG */ - if (bp != NULL) { - if (error) { - bp->b_error = error; - bp->b_flags |= B_ERROR; - bp->b_resid = bp->b_bcount; - } else { - bp->b_error = 0; - bp->b_resid = xs->resid; - } + if (error == EJUSTRETURN) + return (0); - s = splbio(); - biodone(bp); - splx(s); - } + s = splbio(); - if (link->device->done) { - /* - * Tell the device the operation is actually complete. - * No more will happen with this xfer. This for - * notification of the upper-level driver only; they - * won't be returning any meaningful information to us. - */ - link->device->done(xs); - } + if (error == EAGAIN) + scsi_free_xs(xs, 0); /* Don't restart queue. */ + else + scsi_free_xs(xs, 1); - scsi_xs_put(xs); + splx(s); return (error); } -void -scsi_xs_done(struct scsi_xfer *xs) -{ - if (!ISSET(xs->flags, SCSI_POLL)) - wakeup_one(xs); -} - int sc_err1(struct scsi_xfer *xs) { @@ -952,6 +1110,10 @@ scsi_interpret_sense(struct scsi_xfer *xs) sense->flags & SSD_EOM ? 1 : 0, sense->flags & SSD_FILEMARK ? 1 : 0, sense->extra_len)); +#ifdef SCSIDEBUG + if ((sc_link->flags & SDEV_DB1) != 0) + show_mem((u_char *)&xs->sense, sizeof xs->sense); +#endif /* SCSIDEBUG */ /* * If the device has its own error handler, call it first. @@ -1844,3 +2006,57 @@ scsi_decode_sense(struct scsi_sense_data *sense, int flag) return (rqsbuf); } + +#ifdef SCSIDEBUG +/* + * Given a scsi_xfer, dump the request, in all its glory + */ +void +show_scsi_xs(struct scsi_xfer *xs) +{ + u_char *b = (u_char *) xs->cmd; + int i = 0; + + sc_print_addr(xs->sc_link); + + printf("xs(%p): ", xs); + + printf("flg(0x%x)", xs->flags); + printf("sc_link(%p)", xs->sc_link); + printf("retr(0x%x)", xs->retries); + printf("timo(0x%x)", xs->timeout); + printf("cmd(%p)", xs->cmd); + printf("len(0x%x)", xs->cmdlen); + printf("data(%p)", xs->data); + printf("len(0x%x)", xs->datalen); + printf("res(0x%x)", xs->resid); + printf("err(0x%x)", xs->error); + printf("bp(%p)\n", xs->bp); + + printf("command: "); + + if ((xs->flags & SCSI_RESET) == 0) { + while (i < xs->cmdlen) { + if (i) + printf(","); + printf("%x", b[i++]); + } + printf("-[%d bytes]\n", xs->datalen); + } else + printf("-RESET-\n"); +} + +void +show_mem(u_char *address, int num) +{ + int x; + + printf("------------------------------"); + for (x = 0; x < num; x++) { + if ((x % 16) == 0) + printf("\n%03d: ", x); + printf("%02x ", *address++); + } + printf("\n------------------------------\n"); +} +#endif /* SCSIDEBUG */ diff --git a/sys/scsi/scsi_ioctl.c b/sys/scsi/scsi_ioctl.c index f4974a71cf7..6d9b3e17e1c 100644 --- a/sys/scsi/scsi_ioctl.c +++ b/sys/scsi/scsi_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_ioctl.c,v 1.34 2009/10/27 11:24:20 krw Exp $ */ +/* $OpenBSD: scsi_ioctl.c,v 1.35 2009/11/05 03:33:52 marco Exp $ */ /* $NetBSD: scsi_ioctl.c,v 1.23 1996/10/12 23:23:17 christos Exp $ */ /* @@ -52,7 +52,22 @@ #include <scsi/scsiconf.h> #include <sys/scsiio.h> -int scsi_ioc_cmd(struct scsi_link *, scsireq_t *); +struct scsi_ioctl { + LIST_ENTRY(scsi_ioctl) si_list; + struct buf si_bp; + struct uio si_uio; + struct iovec si_iov; + scsireq_t si_screq; + struct scsi_link *si_sc_link; +}; + +LIST_HEAD(, scsi_ioctl) si_head; + +struct scsi_ioctl *si_get(void); +void si_free(struct scsi_ioctl *); +struct scsi_ioctl *si_find(struct buf *); +void scsistrategy(struct buf *); +void scsiminphys(struct buf *); const unsigned char scsi_readsafe_cmd[256] = { [0x00] = 1, /* TEST UNIT READY */ @@ -95,98 +110,237 @@ const unsigned char scsi_readsafe_cmd[256] = { [0xbe] = 1 /* READ CD */ }; -int -scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq) +struct scsi_ioctl * +si_get(void) { - struct scsi_xfer *xs; - int err = 0; - int s; + struct scsi_ioctl *si; + int s; - if (screq->cmdlen > sizeof(struct scsi_generic)) - return (EFAULT); + si = malloc(sizeof(*si), M_TEMP, M_WAITOK | M_ZERO); + s = splbio(); + LIST_INSERT_HEAD(&si_head, si, si_list); + splx(s); + return (si); +} - xs = scsi_xs_get(link, 0); - if (xs == NULL) - return (ENOMEM); +void +si_free(struct scsi_ioctl *si) +{ + int s; - memcpy(xs->cmd, screq->cmd, screq->cmdlen); - xs->cmdlen = screq->cmdlen; + s = splbio(); + LIST_REMOVE(si, si_list); + splx(s); + free(si, M_TEMP); +} + +struct scsi_ioctl * +si_find(struct buf *bp) +{ + struct scsi_ioctl *si; + int s; - if (screq->datalen > 0) { - xs->data = malloc(screq->datalen, M_TEMP, M_WAITOK); - xs->datalen = screq->datalen; + s = splbio(); + LIST_FOREACH(si, &si_head, si_list) { + if (bp == &si->si_bp) + break; } + splx(s); - if (screq->flags & SCCMD_READ) - xs->flags |= SCSI_DATA_IN; - if (screq->flags & SCCMD_WRITE) { - if (screq->datalen > 0) { - err = copyin(screq->databuf, xs->data, screq->datalen); - if (err != 0) - goto err; - } + return (si); +} - xs->flags |= SCSI_DATA_OUT; - } +/* + * We let the user interpret his own sense in the generic scsi world. + * This routine is called at interrupt time if the SCSI_USER bit was set + * in the flags passed to scsi_scsi_cmd(). No other completion processing + * takes place, even if we are running over another device driver. + * The lower level routines that call us here, will free the xs and restart + * the device's queue if such exists. + */ +void +scsi_user_done(struct scsi_xfer *xs) +{ + struct buf *bp; + struct scsi_ioctl *si; + scsireq_t *screq; + struct scsi_link *sc_link; - xs->timeout = screq->timeout; - xs->retries = 0; /* user must do the retries *//* ignored */ + splassert(IPL_BIO); - xs->done = (void (*)(struct scsi_xfer *))wakeup; + bp = xs->bp; + if (bp == NULL) { /* ALL user requests must have a buf */ + sc_print_addr(xs->sc_link); + printf("User command with no buf\n"); + return; + } - scsi_xs_exec(xs); - s = splbio(); - while (!ISSET(xs->flags, ITSDONE)) - tsleep(xs, PRIBIO, "scsiioc", 0); - splx(s); + si = si_find(bp); + if (si == NULL) { + sc_print_addr(xs->sc_link); + printf("User command with no ioctl\n"); + return; + } + + screq = &si->si_screq; + sc_link = si->si_sc_link; + SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n")); screq->retsts = 0; screq->status = xs->status; switch (xs->error) { case XS_NOERROR: + SC_DEBUG(sc_link, SDEV_DB3, ("no error\n")); /* probably rubbish */ screq->datalen_used = xs->datalen - xs->resid; screq->retsts = SCCMD_OK; break; case XS_SENSE: - screq->senselen_used = min(sizeof(xs->sense), - sizeof(screq->sense)); - bcopy(&xs->sense, screq->sense, screq->senselen_used); + SC_DEBUG(sc_link, SDEV_DB3, ("have sense\n")); + screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN); + bcopy(&xs->sense, screq->sense, screq->senselen); screq->retsts = SCCMD_SENSE; break; case XS_SHORTSENSE: - printf("XS_SHORTSENSE\n"); - screq->senselen_used = min(sizeof(xs->sense), - sizeof(screq->sense)); - bcopy(&xs->sense, screq->sense, screq->senselen_used); + SC_DEBUG(sc_link, SDEV_DB3, ("have short sense\n")); + screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN); + bcopy(&xs->sense, screq->sense, screq->senselen); screq->retsts = SCCMD_UNKNOWN; break; case XS_DRIVER_STUFFUP: + sc_print_addr(sc_link); + printf("host adapter code inconsistency\n"); screq->retsts = SCCMD_UNKNOWN; break; case XS_TIMEOUT: + SC_DEBUG(sc_link, SDEV_DB3, ("timeout\n")); screq->retsts = SCCMD_TIMEOUT; break; case XS_BUSY: + SC_DEBUG(sc_link, SDEV_DB3, ("busy\n")); screq->retsts = SCCMD_BUSY; break; default: + sc_print_addr(sc_link); + printf("unknown error category (0x%x) from host adapter code\n", + xs->error); screq->retsts = SCCMD_UNKNOWN; break; } - if (screq->datalen > 0 && screq->flags & SCCMD_READ) { - err = copyout(xs->data, screq->databuf, screq->datalen); - if (err != 0) - goto err; + biodone(bp); /* we're waiting on it in scsi_strategy() */ +} + + +/* Pseudo strategy function + * Called by scsi_do_ioctl() via physio/physstrat if there is to + * be data transferred, and directly if there is no data transfer. + * + * Should I reorganize this so it returns to physio instead + * of sleeping in scsiio_scsi_cmd? Is there any advantage, other + * than avoiding the probable duplicate wakeup in iodone? [PD] + * + * No, seems ok to me... [JRE] + * (I don't see any duplicate wakeups) + * + * Can't be used with block devices or raw_read/raw_write directly + * from the cdevsw/bdevsw tables because they couldn't have added + * the screq structure. [JRE] + */ +void +scsistrategy(struct buf *bp) +{ + struct scsi_ioctl *si; + scsireq_t *screq; + struct scsi_link *sc_link; + int error; + int flags = 0; + int s; + + si = si_find(bp); + if (si == NULL) { + printf("user_strat: No ioctl\n"); + error = EINVAL; + goto bad; + } + + screq = &si->si_screq; + sc_link = si->si_sc_link; + SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n")); + + /* + * We're in trouble if physio tried to break up the transfer. + */ + if (bp->b_bcount != screq->datalen) { + sc_print_addr(sc_link); + printf("physio split the request.. cannot proceed\n"); + error = EIO; + goto bad; + } + + if (screq->timeout == 0) { + error = EINVAL; + goto bad; } -err: - if (screq->datalen > 0) - free(xs->data, M_TEMP); - scsi_xs_put(xs); + if (screq->cmdlen > sizeof(struct scsi_generic)) { + sc_print_addr(sc_link); + printf("cmdlen too big\n"); + error = EFAULT; + goto bad; + } + + if (screq->flags & SCCMD_READ) + flags |= SCSI_DATA_IN; + if (screq->flags & SCCMD_WRITE) + flags |= SCSI_DATA_OUT; + if (screq->flags & SCCMD_TARGET) + flags |= SCSI_TARGET; + if (screq->flags & SCCMD_ESCAPE) + flags |= SCSI_ESCAPE; + + error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)screq->cmd, + screq->cmdlen, (u_char *)bp->b_data, screq->datalen, + 0, /* user must do the retries *//* ignored */ + screq->timeout, bp, flags | SCSI_USER | SCSI_NOSLEEP); + + /* because there is a bp, scsi_scsi_cmd will return immediately */ + if (error) + goto bad; + + SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n")); + s = splbio(); + while ((bp->b_flags & B_DONE) == 0) + tsleep(bp, PRIBIO, "scistr", 0); + splx(s); + SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n")); + + return; + +bad: + bp->b_flags |= B_ERROR; + bp->b_error = error; + s = splbio(); + biodone(bp); + splx(s); +} + +void +scsiminphys(struct buf *bp) +{ + struct scsi_ioctl *si; + struct scsi_link *sc_link; + + si = si_find(bp); + if (si == NULL) { + /* should not happen */ + bp->b_flags |= B_ERROR; + bp->b_error = EINVAL; + return; + } - return (err); + sc_link = si->si_sc_link; + (*sc_link->adapter->scsi_minphys)(bp, sc_link); } /* @@ -200,6 +354,8 @@ int scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) { + int error; + SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd)); switch(cmd) { @@ -222,6 +378,7 @@ scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr, break; /* FALLTHROUGH */ case SCIOCDEBUG: + case SCIOCRESET: if ((flag & FWRITE) == 0) return (EPERM); break; @@ -234,8 +391,41 @@ scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr, } switch(cmd) { - case SCIOCCOMMAND: - return (scsi_ioc_cmd(sc_link, (scsireq_t *)addr)); + case SCIOCCOMMAND: { + scsireq_t *screq = (scsireq_t *)addr; + struct scsi_ioctl *si; + + si = si_get(); + si->si_screq = *screq; + si->si_sc_link = sc_link; + if (screq->datalen) { + si->si_iov.iov_base = screq->databuf; + si->si_iov.iov_len = screq->datalen; + si->si_uio.uio_iov = &si->si_iov; + si->si_uio.uio_iovcnt = 1; + si->si_uio.uio_resid = screq->datalen; + si->si_uio.uio_offset = 0; + si->si_uio.uio_segflg = UIO_USERSPACE; + si->si_uio.uio_rw = + (screq->flags & SCCMD_READ) ? UIO_READ : UIO_WRITE; + si->si_uio.uio_procp = p; + error = physio(scsistrategy, &si->si_bp, dev, + (screq->flags & SCCMD_READ) ? B_READ : B_WRITE, + scsiminphys, &si->si_uio); + } else { + /* if no data, no need to translate it.. */ + si->si_bp.b_flags = 0; + si->si_bp.b_data = 0; + si->si_bp.b_bcount = 0; + si->si_bp.b_dev = dev; + si->si_bp.b_proc = p; + scsistrategy(&si->si_bp); + error = si->si_bp.b_error; + } + *screq = si->si_screq; + si_free(si); + return (error); + } case SCIOCDEBUG: { int level = *((int *)addr); @@ -251,6 +441,11 @@ scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr, sc_link->flags |= SDEV_DB4; return (0); } + case SCIOCRESET: { + scsi_scsi_cmd(sc_link, 0, 0, 0, 0, GENRETRY, 2000, NULL, + SCSI_RESET); + return (0); + } default: #ifdef DIAGNOSTIC panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd); diff --git a/sys/scsi/scsiconf.c b/sys/scsi/scsiconf.c index 431cd0e029c..f3bacce6b96 100644 --- a/sys/scsi/scsiconf.c +++ b/sys/scsi/scsiconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.c,v 1.147 2009/10/23 01:02:29 dlg Exp $ */ +/* $OpenBSD: scsiconf.c,v 1.148 2009/11/05 03:33:52 marco Exp $ */ /* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */ /* @@ -113,10 +113,6 @@ int scsi_autoconf = SCSI_AUTOCONF; int scsibusprint(void *, const char *); void scsibus_printlink(struct scsi_link *); -void scsi_activate_bus(struct scsibus_softc *, int); -void scsi_activate_target(struct scsibus_softc *, int, int); -void scsi_activate_lun(struct scsibus_softc *, int, int, int); - const u_int8_t version_to_spc [] = { 0, /* 0x00: The device does not claim conformance to any standard. */ 1, /* 0x01: (Obsolete) SCSI-1 in olden times. */ @@ -203,99 +199,30 @@ scsibusattach(struct device *parent, struct device *self, void *aux) int scsibusactivate(struct device *dev, int act) { - struct scsibus_softc *sc = (struct scsibus_softc *)dev; - - scsi_activate(sc, -1, -1, act); - - return (0); -} - -void -scsi_activate(struct scsibus_softc *sc, int target, int lun, int act) -{ - if (target == -1 && lun == -1) - scsi_activate_bus(sc, act); - - if (target == -1) - return; - - if (lun == -1) - scsi_activate_target(sc, target, act); - - scsi_activate_lun(sc, target, lun, act); -} - -void -scsi_activate_bus(struct scsibus_softc *sc, int act) -{ - int target; - - for (target = 0; target < sc->sc_buswidth; target++) - scsi_activate_target(sc, target, act); -} - -void -scsi_activate_target(struct scsibus_softc *sc, int target, int act) -{ - int lun; - - for (lun = 0; lun < sc->adapter_link->luns; lun++) - scsi_activate_lun(sc, target, lun, act); -} - -void -scsi_activate_lun(struct scsibus_softc *sc, int target, int lun, int act) -{ - struct scsi_link *link = sc->sc_link[target][lun]; - struct device *dev; - - if (link == NULL) - return; - - dev = link->device_softc; - switch (act) { - case DVACT_ACTIVATE: -#if NMPATH > 0 - if (dev == NULL) - mpath_path_activate(link); - else -#endif /* NMPATH */ - config_activate(dev); - break; - - case DVACT_DEACTIVATE: -#if NMPATH > 0 - if (dev == NULL) - mpath_path_deactivate(link); - else -#endif /* NMPATH */ - config_deactivate(dev); - break; - default: -#ifdef DIAGNOSTIC - printf("%s: unsupported act %d\n", sc->sc_dev.dv_xname, act); -#endif - break; - } + return (config_activate_children(dev, act)); } int scsibusdetach(struct device *dev, int type) { struct scsibus_softc *sb = (struct scsibus_softc *)dev; - int i, error; + int i, j, error; #if NBIO > 0 bio_unregister(&sb->sc_dev); #endif - error = scsi_detach_bus(sb, type); - if (error != 0) + if ((error = config_detach_children(dev, type)) != 0) return (error); for (i = 0; i < sb->sc_buswidth; i++) { - if (sb->sc_link[i] != NULL) + if (sb->sc_link[i] != NULL) { + for (j = 0; j < sb->adapter_link->luns; j++) { + if (sb->sc_link[i][j] != NULL) + free(sb->sc_link[i][j], M_DEVBUF); + } free(sb->sc_link[i], M_DEVBUF); + } } free(sb->sc_link, M_DEVBUF); @@ -347,9 +274,6 @@ scsibus_bioctl(struct device *dev, u_long cmd, caddr_t addr) case SBIOCDETACH: sdev = (struct sbioc_device *)addr; - if (sdev->sd_target == -1 && sdev->sd_lun == -1) - return (scsi_detach_bus(sc, 0)); - if (sdev->sd_target == -1) return (EINVAL); @@ -455,22 +379,19 @@ int scsi_detach_bus(struct scsibus_softc *sc, int flags) { struct scsi_link *alink = sc->adapter_link; - int i, err, rv = 0; + int i; - for (i = 0; i < alink->adapter_buswidth; i++) { - err = scsi_detach_target(sc, i, flags); - if (err != 0 && err != ENXIO) - rv = err; - } + for (i = 0; i < alink->adapter_buswidth; i++) + scsi_detach_target(sc, i, flags); - return (rv); + return (0); } int scsi_detach_target(struct scsibus_softc *sc, int target, int flags) { struct scsi_link *alink = sc->adapter_link; - int i, err, rv = 0; + int i, err, rv = 0, detached = 0; if (target < 0 || target >= alink->adapter_buswidth || target == alink->adapter_target) @@ -484,11 +405,12 @@ scsi_detach_target(struct scsibus_softc *sc, int target, int flags) continue; err = scsi_detach_lun(sc, target, i, flags); - if (err != 0 && err != ENXIO) + if (err != 0) rv = err; + detached = 1; } - return (rv); + return (detached ? rv : ENXIO); } int @@ -531,8 +453,6 @@ scsi_detach_lun(struct scsibus_softc *sc, int target, int lun, int flags) alink->adapter->dev_free(link); /* 3. free up its state in the midlayer */ - if (link->id != NULL) - devid_free(link->id); free(link, M_DEVBUF); sc->sc_link[target][lun] = NULL; @@ -765,42 +685,6 @@ scsibus_printlink(struct scsi_link *link) printf("SCSI%d", SCSISPC(inqbuf->version)); printf(" %d/%s %s%s", type, dtype, removable ? "removable" : "fixed", qtype); - -#if NMPATH > 0 - if (link->id != NULL && link->id->d_type != DEVID_NONE) { - u_int8_t *id = (u_int8_t *)(link->id + 1); - int i; - - switch (link->id->d_type) { - case DEVID_NAA: - printf(" naa."); - break; - case DEVID_EUI: - printf(" eui."); - break; - case DEVID_T10: - printf(" t10."); - break; - } - - if (ISSET(link->id->d_flags, DEVID_F_PRINT)) { - for (i = 0; i < link->id->d_len; i++) { - if (id[i] == '\0' || id[i] == ' ') - printf("_"); - else if (id[i] < 0x20 || id[i] >= 0x80) { - /* non-printable characters */ - printf("~"); - } else { - /* normal characters */ - printf("%c", id[i]); - } - } - } else { - for (i = 0; i < link->id->d_len; i++) - printf("%02x", id[i]); - } - } -#endif /* NMPATH > 0 */ } /* @@ -854,7 +738,6 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun) sc_link->target = target; sc_link->lun = lun; sc_link->device = &probe_switch; - mtx_init(&sc_link->mtx, IPL_BIO); inqbuf = &sc_link->inqdata; SC_DEBUG(sc_link, SDEV_DB2, ("scsi_link created.\n")); @@ -927,14 +810,15 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun) ; else if (sc_link->flags & SDEV_UMASS) ; - else if (!DEVID_CMP(scsi->sc_link[target][0]->id, sc_link->id)) + else if (sc_link->id.d_type != DEVID_NONE && + !DEVID_CMP(&scsi->sc_link[target][0]->id, &sc_link->id)) ; else if (memcmp(inqbuf, &scsi->sc_link[target][0]->inqdata, sizeof(*inqbuf)) == 0) { /* The device doesn't distinguish between LUNs. */ SC_DEBUG(sc_link, SDEV_DB1, ("IDENTIFY not supported.\n")); rslt = EINVAL; - goto free_devid; + goto bad; } #if NMPATH > 0 @@ -988,7 +872,7 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun) &sa)) == 0) { scsibusprint(&sa, scsi->sc_dev.dv_xname); printf(" not configured\n"); - goto free_devid; + goto bad; } /* @@ -1025,9 +909,6 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun) return (0); -free_devid: - if (sc_link->id) - devid_free(sc_link->id); bad: if (scsi->adapter_link->adapter->dev_free != NULL) scsi->adapter_link->adapter->dev_free(sc_link); @@ -1098,9 +979,6 @@ scsi_devid(struct scsi_link *link) } __packed pg; int pg80 = 0, pg83 = 0, i; - if (link->id != NULL) - return; - if (SCSISPC(link->inqdata.version) >= 2) { if (scsi_inquire_vpd(link, &pg, sizeof(pg), SI_PG_SUPPORTED, scsi_autoconf) != 0) @@ -1130,10 +1008,9 @@ int scsi_devid_pg83(struct scsi_link *link) { struct scsi_vpd_hdr hdr; - struct scsi_vpd_devid_hdr dhdr, chdr; + struct scsi_vpd_devid_hdr dhdr; u_int8_t *pg, *id; - int type, idtype = 0; - u_char idflags; + int type, idtype = 0, idlen; int len, pos; int rv; @@ -1171,8 +1048,7 @@ scsi_devid_pg83(struct scsi_link *link) case VPD_DEVID_TYPE_T10: if (type >= idtype) { idtype = type; - - chdr = dhdr; + idlen = dhdr.len; id = &pg[pos]; } break; @@ -1187,27 +1063,21 @@ scsi_devid_pg83(struct scsi_link *link) } while (idtype != VPD_DEVID_TYPE_NAA && len != pos); if (idtype > 0) { - switch (VPD_DEVID_TYPE(chdr.flags)) { + link->id.d_id = malloc(idlen, M_DEVBUF, M_WAITOK); + + switch (idtype) { case VPD_DEVID_TYPE_NAA: - idtype = DEVID_NAA; + link->id.d_type = DEVID_NAA; break; case VPD_DEVID_TYPE_EUI64: - idtype = DEVID_EUI; + link->id.d_type = DEVID_EUI; break; case VPD_DEVID_TYPE_T10: - idtype = DEVID_T10; + link->id.d_type = DEVID_T10; break; } - switch (VPD_DEVID_CODE(chdr.pi_code)) { - case VPD_DEVID_CODE_ASCII: - case VPD_DEVID_CODE_UTF8: - idflags = DEVID_F_PRINT; - break; - default: - idflags = 0; - break; - } - link->id = devid_alloc(idtype, idflags, chdr.len, id); + link->id.d_len = idlen; + memcpy(link->id.d_id, id, idlen); } else rv = ENODEV; @@ -1225,35 +1095,3 @@ scsi_minphys(struct buf *bp, struct scsi_link *sl) { minphys(bp); } - -struct devid * -devid_alloc(u_int8_t type, u_int8_t flags, u_int8_t len, u_int8_t *id) -{ - struct devid *d; - - d = malloc(sizeof(*d) + len, M_DEVBUF, M_WAITOK|M_CANFAIL); - if (d == NULL) - return (NULL); - - d->d_type = type; - d->d_flags = flags; - d->d_len = len; - d->d_refcount = 1; - memcpy(d + 1, id, len); - - return (d); -} - -struct devid * -devid_copy(struct devid *d) -{ - d->d_refcount++; - return (d); -} - -void -devid_free(struct devid *d) -{ - if (--d->d_refcount == 0) - free(d, M_DEVBUF); -} diff --git a/sys/scsi/scsiconf.h b/sys/scsi/scsiconf.h index f3039640b3d..244ff1817a7 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.h,v 1.105 2009/10/23 01:02:29 dlg Exp $ */ +/* $OpenBSD: scsiconf.h,v 1.106 2009/11/05 03:33:52 marco Exp $ */ /* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */ /* @@ -53,7 +53,6 @@ #include <sys/queue.h> #include <sys/timeout.h> #include <sys/workq.h> -#include <sys/mutex.h> #include <machine/cpu.h> #include <scsi/scsi_debug.h> @@ -235,31 +234,20 @@ _4ltol(u_int8_t *bytes) #define DEVID_T10 3 struct devid { - u_int8_t d_type; - u_int8_t d_flags; -#define DEVID_F_PRINT (1<<0) - u_int8_t d_refcount; - u_int8_t d_len; - - /* - * the devid struct is basically a header, the actual id is allocated - * immediately after it. - */ + int d_type; + u_int d_len; + u_int8_t *d_id; }; -#define DEVID_CMP(_a, _b) ( \ - (_a) != NULL && (_b) != NULL && \ - ((_a) == (_b) || \ - ((_a)->d_type != DEVID_NONE && \ - (_a)->d_type == (_b)->d_type && \ - (_a)->d_len == (_b)->d_len && \ - bcmp((_a) + 1, (_b) + 1, (_a)->d_len) == 0)) \ +#define DEVID_CMP(_a, _b) ( \ + (_a) != NULL && \ + (_b) != NULL && \ + (_a)->d_type != DEVID_NONE && \ + (_a)->d_type == (_b)->d_type && \ + (_a)->d_len == (_b)->d_len && \ + bcmp((_a)->d_id, (_b)->d_id, (_a)->d_len) == 0 \ ) -struct devid * devid_alloc(u_int8_t, u_int8_t, u_int8_t, u_int8_t *); -struct devid * devid_copy(struct devid *); -void devid_free(struct devid *); - /* * The following documentation tries to describe the relationship between the * various structures defined in this file: @@ -351,6 +339,7 @@ struct scsi_link { u_int64_t node_wwn; /* world wide name of node */ u_int16_t adapter_target; /* what are we on the scsi bus */ u_int16_t adapter_buswidth; /* 8 (regular) or 16 (wide). (0 becomes 8) */ + u_int16_t active; /* operations in progress */ u_int16_t flags; /* flags that all devices have */ #define SDEV_REMOVABLE 0x0001 /* media is removable */ #define SDEV_MEDIA_LOADED 0x0002 /* device figures are still valid */ @@ -379,8 +368,7 @@ struct scsi_link { void *adapter_softc; /* needed for call to foo_scsi_cmd */ struct scsibus_softc *bus; /* link to the scsibus we're on */ struct scsi_inquiry_data inqdata; /* copy of INQUIRY data from probe */ - struct devid *id; - struct mutex mtx; + struct devid id; }; int scsiprint(void *, const char *); @@ -456,8 +444,6 @@ struct scsi_xfer { * timeout structure for hba's to use for a command */ struct timeout stimeout; - void *cookie; - void (*done)(struct scsi_xfer *); }; /* @@ -571,23 +557,14 @@ int scsi_detach_lun(struct scsibus_softc *, int, int, int); int scsi_req_probe(struct scsibus_softc *, int, int); int scsi_req_detach(struct scsibus_softc *, int, int, int); -void scsi_activate(struct scsibus_softc *, int, int, int); - extern const u_int8_t version_to_spc[]; #define SCSISPC(x)(version_to_spc[(x) & SID_ANSII]) -struct scsi_xfer * scsi_xs_get(struct scsi_link *, int); -void scsi_xs_exec(struct scsi_xfer *); -void scsi_xs_put(struct scsi_xfer *); - /* * Entrypoints for multipathing */ int mpath_path_attach(struct scsi_link *); int mpath_path_detach(struct scsi_link *, int); -void mpath_path_activate(struct scsi_link *); -void mpath_path_deactivate(struct scsi_link *); - #endif /* _KERNEL */ #endif /* SCSI_SCSICONF_H */ diff --git a/sys/scsi/sd.c b/sys/scsi/sd.c index ac3b6811de4..96044fe76a4 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sd.c,v 1.160 2009/10/21 20:32:02 marco Exp $ */ +/* $OpenBSD: sd.c,v 1.161 2009/11/05 03:33:52 marco Exp $ */ /* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */ /*- @@ -83,7 +83,10 @@ int sddetach(struct device *, int); void sdminphys(struct buf *); int sdgetdisklabel(dev_t, struct sd_softc *, struct disklabel *, int); void sdstart(void *); +void sdrestart(void *); +void sddone(struct scsi_xfer *); void sd_shutdown(void *); +int sd_reassign_blocks(struct sd_softc *, u_long); int sd_interpret_sense(struct scsi_xfer *); int sd_get_parms(struct sd_softc *, struct disk_parms *, int); void sd_flush(struct sd_softc *, int); @@ -93,16 +96,6 @@ void viscpy(u_char *, u_char *, int); int sd_ioctl_inquiry(struct sd_softc *, struct dk_inquiry *); -struct buf *sd_buf_dequeue(struct sd_softc *); -void sd_buf_requeue(struct sd_softc *, struct buf *); - -void sd_cmd_rw6(struct scsi_xfer *, int, daddr64_t, u_int); -void sd_cmd_rw10(struct scsi_xfer *, int, daddr64_t, u_int); -void sd_cmd_rw12(struct scsi_xfer *, int, daddr64_t, u_int); -void sd_cmd_rw16(struct scsi_xfer *, int, daddr64_t, u_int); - -void sd_buf_done(struct scsi_xfer *); - struct cfattach sd_ca = { sizeof(struct sd_softc), sdmatch, sdattach, sddetach, sdactivate @@ -118,7 +111,7 @@ struct scsi_device sd_switch = { sd_interpret_sense, /* check out error handler first */ sdstart, /* have a queue, served by this */ NULL, /* have no async handler */ - NULL, /* have no done handler */ + sddone, /* deal with stats at interrupt time */ }; const struct scsi_inquiry_pattern sd_patterns[] = { @@ -170,8 +163,6 @@ sdattach(struct device *parent, struct device *self, void *aux) SC_DEBUG(sc_link, SDEV_DB2, ("sdattach:\n")); - mtx_init(&sd->sc_buf_mtx, IPL_BIO); - /* * Store information needed to contact our base driver */ @@ -206,7 +197,7 @@ sdattach(struct device *parent, struct device *self, void *aux) */ printf("\n"); - timeout_set(&sd->sc_timeout, sdstart, sd); + timeout_set(&sd->sc_timeout, sdrestart, sd); /* Spin up non-UMASS devices ready or not. */ if ((sd->sc_link->flags & SDEV_UMASS) == 0) @@ -560,12 +551,12 @@ sdstrategy(struct buf *bp) (sd->flags & (SDF_WLABEL|SDF_LABELLING)) != 0) <= 0) goto done; + s = splbio(); + /* * Place it in the queue of disk activities for this disk */ - mtx_enter(&sd->sc_buf_mtx); - disksort(&sd->sc_buf_queue, bp); - mtx_leave(&sd->sc_buf_mtx); + disksort(&sd->buf_queue, bp); /* * Tell the device to get going on the transfer if it's @@ -573,6 +564,8 @@ sdstrategy(struct buf *bp) */ sdstart(sd); + splx(s); + device_unref(&sd->sc_dev); return; @@ -590,77 +583,6 @@ done: device_unref(&sd->sc_dev); } -struct buf * -sd_buf_dequeue(struct sd_softc *sc) -{ - struct buf *bp; - - mtx_enter(&sc->sc_buf_mtx); - bp = sc->sc_buf_queue.b_actf; - if (bp != NULL) - sc->sc_buf_queue.b_actf = bp->b_actf; - mtx_leave(&sc->sc_buf_mtx); - - return (bp); -} - -void -sd_buf_requeue(struct sd_softc *sc, struct buf *bp) -{ - mtx_enter(&sc->sc_buf_mtx); - bp->b_actf = sc->sc_buf_queue.b_actf; - sc->sc_buf_queue.b_actf = bp; - mtx_leave(&sc->sc_buf_mtx); -} - -void -sd_cmd_rw6(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks) -{ - struct scsi_rw *cmd = (struct scsi_rw *)xs->cmd; - - cmd->opcode = read ? READ_COMMAND : WRITE_COMMAND; - _lto3b(blkno, cmd->addr); - cmd->length = nblks; - - xs->cmdlen = sizeof(*cmd); -} - -void -sd_cmd_rw10(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks) -{ - struct scsi_rw_big *cmd = (struct scsi_rw_big *)xs->cmd; - - cmd->opcode = read ? READ_BIG : WRITE_BIG; - _lto4b(blkno, cmd->addr); - _lto2b(nblks, cmd->length); - - xs->cmdlen = sizeof(*cmd); -} - -void -sd_cmd_rw12(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks) -{ - struct scsi_rw_12 *cmd = (struct scsi_rw_12 *)xs->cmd; - - cmd->opcode = read ? READ_12 : WRITE_12; - _lto4b(blkno, cmd->addr); - _lto4b(nblks, cmd->length); - - xs->cmdlen = sizeof(*cmd); -} - -void -sd_cmd_rw16(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks) -{ - struct scsi_rw_16 *cmd = (struct scsi_rw_16 *)xs->cmd; - - cmd->opcode = read ? READ_16 : WRITE_16; - _lto8b(blkno, cmd->addr); - _lto4b(nblks, cmd->length); - - xs->cmdlen = sizeof(*cmd); -} - /* * sdstart looks to see if there is a buf waiting for the device * and that the device is not already busy. If both are true, @@ -673,31 +595,62 @@ sd_cmd_rw16(struct scsi_xfer *xs, int read, daddr64_t blkno, u_int nblks) * This routine is also called after other non-queued requests * have been made of the scsi driver, to ensure that the queue * continues to be drained. + * + * must be called at the correct (highish) spl level + * sdstart() is called at splbio from sdstrategy, sdrestart and scsi_done */ void sdstart(void *v) { - struct sd_softc *sc = (struct sd_softc *)v; - struct scsi_link *link = sc->sc_link; - struct scsi_xfer *xs; - struct buf *bp; + struct sd_softc *sd = (struct sd_softc *)v; + struct scsi_link *sc_link = sd->sc_link; + struct buf *bp = 0; + struct buf *dp; + struct scsi_rw_big cmd_big; + struct scsi_rw_12 cmd_12; + struct scsi_rw_16 cmd_16; + struct scsi_rw cmd_small; + struct scsi_generic *cmdp; daddr64_t blkno; - int nblks; - int read; + int nblks, cmdlen, error; struct partition *p; - if (sc->flags & SDF_DYING) + if (sd->flags & SDF_DYING) return; SC_DEBUG(sc_link, SDEV_DB2, ("sdstart\n")); - while ((bp = sd_buf_dequeue(sc)) != NULL) { + splassert(IPL_BIO); + + /* + * Check if the device has room for another command + */ + while (sc_link->openings > 0) { + /* + * there is excess capacity, but a special waits + * It'll need the adapter as soon as we clear out of the + * way and let it run (user level wait). + */ + if (sc_link->flags & SDEV_WAITING) { + sc_link->flags &= ~SDEV_WAITING; + wakeup((caddr_t)sc_link); + return; + } + + /* + * See if there is a buf with work for us to do.. + */ + dp = &sd->buf_queue; + if ((bp = dp->b_actf) == NULL) /* yes, an assign */ + return; + dp->b_actf = bp->b_actf; + /* * If the device has become invalid, abort all the * reads and writes until all files have been closed and * re-opened */ - if ((link->flags & SDEV_MEDIA_LOADED) == 0) { + if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) { bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; @@ -705,77 +658,129 @@ sdstart(void *v) continue; } - xs = scsi_xs_get(link, SCSI_NOSLEEP); - if (xs == NULL) { - sd_buf_requeue(sc, bp); - return; - } - + /* + * We have a buf, now we should make a command + * + * First, translate the block to absolute and put it in terms + * of the logical blocksize of the device. + */ blkno = - bp->b_blkno / (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE); - p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; + bp->b_blkno / (sd->sc_dk.dk_label->d_secsize / DEV_BSIZE); + p = &sd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; blkno += DL_GETPOFFSET(p); - nblks = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize); - read = bp->b_flags & B_READ; + nblks = howmany(bp->b_bcount, sd->sc_dk.dk_label->d_secsize); /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ - if (!(link->flags & SDEV_ATAPI) && - !(link->quirks & SDEV_ONLYBIG) && + if (!(sc_link->flags & SDEV_ATAPI) && + !(sc_link->quirks & SDEV_ONLYBIG) && ((blkno & 0x1fffff) == blkno) && - ((nblks & 0xff) == nblks)) - sd_cmd_rw6(xs, read, blkno, nblks); - else if (((blkno & 0xffffffff) == blkno) && - ((nblks & 0xffff) == nblks)) - sd_cmd_rw10(xs, read, blkno, nblks); - else if (((blkno & 0xffffffff) == blkno) && - ((nblks & 0xffffffff) == nblks)) - sd_cmd_rw12(xs, read, blkno, nblks); - else - sd_cmd_rw16(xs, read, blkno, nblks); - - xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT); - xs->timeout = 60000; - xs->data = bp->b_data; - xs->datalen = bp->b_bcount; - - xs->done = sd_buf_done; - xs->cookie = bp; + ((nblks & 0xff) == nblks)) { + /* + * We can fit in a 6 byte cdb. + */ + bzero(&cmd_small, sizeof(cmd_small)); + cmd_small.opcode = (bp->b_flags & B_READ) ? + READ_COMMAND : WRITE_COMMAND; + _lto3b(blkno, cmd_small.addr); + cmd_small.length = nblks; + cmdlen = sizeof(cmd_small); + cmdp = (struct scsi_generic *)&cmd_small; + } else if (((blkno & 0xffffffff) == blkno) && + ((nblks & 0xffff) == nblks)) { + /* + * We can fit in a 10 byte cdb. + */ + bzero(&cmd_big, sizeof(cmd_big)); + cmd_big.opcode = (bp->b_flags & B_READ) ? + READ_BIG : WRITE_BIG; + _lto4b(blkno, cmd_big.addr); + _lto2b(nblks, cmd_big.length); + cmdlen = sizeof(cmd_big); + cmdp = (struct scsi_generic *)&cmd_big; + } else if (((blkno & 0xffffffff) == blkno) && + ((nblks & 0xffffffff) == nblks)) { + /* + * We can fit in a 12 byte cdb. + */ + bzero(&cmd_12, sizeof(cmd_12)); + cmd_12.opcode = (bp->b_flags & B_READ) ? + READ_12 : WRITE_12; + _lto4b(blkno, cmd_12.addr); + _lto4b(nblks, cmd_12.length); + cmdlen = sizeof(cmd_12); + cmdp = (struct scsi_generic *)&cmd_12; + } else { + /* + * Need a 16 byte cdb. There's nothing bigger. + */ + bzero(&cmd_16, sizeof(cmd_16)); + cmd_16.opcode = (bp->b_flags & B_READ) ? + READ_16 : WRITE_16; + _lto8b(blkno, cmd_16.addr); + _lto4b(nblks, cmd_16.length); + cmdlen = sizeof(cmd_16); + cmdp = (struct scsi_generic *)&cmd_16; + } /* Instrumentation. */ - disk_busy(&sc->sc_dk); - scsi_xs_exec(xs); + disk_busy(&sd->sc_dk); + + /* + * Call the routine that chats with the adapter. + * Note: we cannot sleep as we may be an interrupt + */ + error = scsi_scsi_cmd(sc_link, cmdp, cmdlen, + (u_char *)bp->b_data, bp->b_bcount, + SCSI_RETRIES, 60000, bp, SCSI_NOSLEEP | + ((bp->b_flags & B_READ) ? SCSI_DATA_IN : SCSI_DATA_OUT)); + switch (error) { + case 0: + /* + * Mark the disk dirty so that the cache will be + * flushed on close. + */ + if ((bp->b_flags & B_READ) == 0) + sd->flags |= SDF_DIRTY; + timeout_del(&sd->sc_timeout); + break; + case EAGAIN: + /* + * The device can't start another i/o. Try again later. + */ + dp->b_actf = bp; + disk_unbusy(&sd->sc_dk, 0, 0); + timeout_add(&sd->sc_timeout, 1); + return; + default: + disk_unbusy(&sd->sc_dk, 0, 0); + printf("%s: not queued, error %d\n", + sd->sc_dev.dv_xname, error); + break; + } } } void -sd_buf_done(struct scsi_xfer *xs) +sdrestart(void *v) { - struct sd_softc *sc = xs->sc_link->device_softc; - struct buf *bp = xs->cookie; int s; - disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid, - bp->b_flags & B_READ); - - if (xs->error == XS_NOERROR) { - bp->b_error = 0; - bp->b_resid = xs->resid; - } else { - bp->b_error = EIO; - bp->b_flags |= B_ERROR; - bp->b_resid = bp->b_bcount; - } - s = splbio(); - biodone(bp); + sdstart(v); splx(s); +} - scsi_xs_put(xs); +void +sddone(struct scsi_xfer *xs) +{ + struct sd_softc *sd = xs->sc_link->device_softc; - sdstart(sc); /* XXX */ + if (xs->bp != NULL) + disk_unbusy(&sd->sc_dk, (xs->bp->b_bcount - xs->bp->b_resid), + (xs->bp->b_flags & B_READ)); } void @@ -1076,6 +1081,27 @@ sd_shutdown(void *arg) } /* + * Tell the device to map out a defective block + */ +int +sd_reassign_blocks(struct sd_softc *sd, u_long blkno) +{ + struct scsi_reassign_blocks scsi_cmd; + struct scsi_reassign_blocks_data rbdata; + + bzero(&scsi_cmd, sizeof(scsi_cmd)); + bzero(&rbdata, sizeof(rbdata)); + scsi_cmd.opcode = REASSIGN_BLOCKS; + + _lto2b(sizeof(rbdata.defect_descriptor[0]), rbdata.length); + _lto4b(blkno, rbdata.defect_descriptor[0].dlbaddr); + + return scsi_scsi_cmd(sd->sc_link, (struct scsi_generic *)&scsi_cmd, + sizeof(scsi_cmd), (u_char *)&rbdata, sizeof(rbdata), SCSI_RETRIES, + 5000, NULL, SCSI_DATA_OUT); +} + +/* * Check Errors */ int @@ -1160,6 +1186,7 @@ sdsize(dev_t dev) } /* #define SD_DUMP_NOT_TRUSTED if you just want to watch */ +static struct scsi_xfer sx; static int sddoingadump; /* @@ -1169,7 +1196,7 @@ static int sddoingadump; int sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) { - struct sd_softc *sc; /* disk unit to do the I/O */ + struct sd_softc *sd; /* disk unit to do the I/O */ struct disklabel *lp; /* disk's disklabel */ int unit, part; int sectorsize; /* size of a disk sector */ @@ -1177,7 +1204,9 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) daddr64_t sectoff; /* sector offset of partition */ int totwrt; /* total number of sectors left to write */ int nwrt; /* current number of sectors to write */ + struct scsi_rw_big cmd; /* write command */ struct scsi_xfer *xs; /* ... convenience */ + int retval; /* Check if recursive dump; if so, punt. */ if (sddoingadump) @@ -1190,7 +1219,7 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) part = DISKPART(dev); /* Check for acceptable drive number. */ - if (unit >= sd_cd.cd_ndevs || (sc = sd_cd.cd_devs[unit]) == NULL) + if (unit >= sd_cd.cd_ndevs || (sd = sd_cd.cd_devs[unit]) == NULL) return ENXIO; /* @@ -1200,12 +1229,12 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) */ #if 0 /* Make sure it was initialized. */ - if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED) + if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED) return ENXIO; #endif /* Convert to disk sectors. Request must be a multiple of size. */ - lp = sc->sc_dk.dk_label; + lp = sd->sc_dk.dk_label; sectorsize = lp->d_secsize; if ((size % sectorsize) != 0) return EFAULT; @@ -1222,25 +1251,43 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) /* Offset block number to start of partition. */ blkno += sectoff; + xs = &sx; + while (totwrt > 0) { nwrt = totwrt; /* XXX */ - #ifndef SD_DUMP_NOT_TRUSTED - xs = scsi_xs_get(sc->sc_link, SCSI_NOSLEEP); - if (xs == NULL) - return (ENOMEM); - - xs->timeout = 10000; - xs->flags = SCSI_POLL | SCSI_NOSLEEP | SCSI_DATA_OUT; + /* + * Fill out the scsi command + */ + bzero(&cmd, sizeof(cmd)); + cmd.opcode = WRITE_BIG; + _lto4b(blkno, cmd.addr); + _lto2b(nwrt, cmd.length); + /* + * Fill out the scsi_xfer structure + * Note: we cannot sleep as we may be an interrupt + * don't use scsi_scsi_cmd() as it may want + * to wait for an xs. + */ + bzero(xs, sizeof(sx)); + xs->flags |= SCSI_AUTOCONF | SCSI_DATA_OUT; + xs->sc_link = sd->sc_link; + xs->retries = SCSI_RETRIES; + xs->timeout = 10000; /* 10000 millisecs for a disk ! */ + xs->cmd = (struct scsi_generic *)&cmd; + xs->cmdlen = sizeof(cmd); + xs->resid = nwrt * sectorsize; + xs->error = XS_NOERROR; + xs->bp = NULL; xs->data = va; xs->datalen = nwrt * sectorsize; - sd_cmd_rw10(xs, 0, blkno, nwrt); /* XXX */ - - scsi_xs_exec(xs); - if (xs->error != XS_NOERROR) - return (ENXIO); - scsi_xs_put(xs); + /* + * Pass all this info to the scsi driver. + */ + retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs); + if (retval != COMPLETE) + return ENXIO; #else /* SD_DUMP_NOT_TRUSTED */ /* Let's just talk about this first... */ printf("sd%d: dump addr 0x%x, blk %d\n", unit, va, blkno); @@ -1252,10 +1299,8 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) blkno += nwrt; va += sectorsize * nwrt; } - sddoingadump = 0; - - return (0); + return 0; } /* @@ -1424,17 +1469,14 @@ validate: return (SDGP_RESULT_OK); } -void -sd_flush_done(struct scsi_xfer *xs); void -sd_flush(struct sd_softc *sc, int flags) +sd_flush(struct sd_softc *sd, int flags) { - struct scsi_link *link = sc->sc_link; - struct scsi_xfer *xs; - struct scsi_synchronize_cache *cmd; + struct scsi_link *sc_link = sd->sc_link; + struct scsi_synchronize_cache cmd; - if (link->quirks & SDEV_NOSYNCCACHE) + if (sc_link->quirks & SDEV_NOSYNCCACHE) return; /* @@ -1443,38 +1485,15 @@ sd_flush(struct sd_softc *sc, int flags) * that the command is not supported by the device. */ - xs = scsi_xs_get(link, flags); - if (xs == NULL) { - SC_DEBUG(sc_link, SDEV_DB1, ("cache sync failed to get xs\n")); - return; - } - - cmd = (struct scsi_synchronize_cache *)xs->cmd; - cmd->opcode = SYNCHRONIZE_CACHE; - - xs->timeout = 100000; - - xs->done = sd_flush_done; - - scsi_xs_exec(xs); - if (!ISSET(xs->flags, SCSI_POLL)) { - while (!ISSET(xs->flags, ITSDONE)) - tsleep(xs, PRIBIO, "sdflush", 0); - } - - if (xs->error != XS_NOERROR) + bzero(&cmd, sizeof(cmd)); + cmd.opcode = SYNCHRONIZE_CACHE; + + if (scsi_scsi_cmd(sc_link, (struct scsi_generic *)&cmd, sizeof(cmd), + NULL, 0, SCSI_RETRIES, 100000, NULL, + flags | SCSI_IGNORE_ILLEGAL_REQUEST)) { SC_DEBUG(sc_link, SDEV_DB1, ("cache sync failed\n")); - else - sc->flags &= ~SDF_DIRTY; - - scsi_xs_put(xs); -} - -void -sd_flush_done(struct scsi_xfer *xs) -{ - if (!ISSET(xs->flags, SCSI_POLL)) - wakeup_one(xs); + } else + sd->flags &= ~SDF_DIRTY; } /* @@ -1483,11 +1502,16 @@ sd_flush_done(struct scsi_xfer *xs) void sd_kill_buffers(struct sd_softc *sd) { - struct buf *bp; + struct buf *dp, *bp; + int s; + + s = splbio(); + for (dp = &sd->buf_queue; (bp = dp->b_actf) != NULL; ) { + dp->b_actf = bp->b_actf; - while ((bp = sd_buf_dequeue(sd)) != NULL) { bp->b_error = ENXIO; bp->b_flags |= B_ERROR; biodone(bp); } + splx(s); } diff --git a/sys/scsi/sdvar.h b/sys/scsi/sdvar.h index f17ad6e2d36..af65a746a54 100644 --- a/sys/scsi/sdvar.h +++ b/sys/scsi/sdvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdvar.h,v 1.19 2009/09/14 00:03:28 dlg Exp $ */ +/* $OpenBSD: sdvar.h,v 1.20 2009/11/05 03:33:52 marco Exp $ */ /* $NetBSD: sdvar.h,v 1.7 1998/08/17 00:49:03 mycroft Exp $ */ /*- @@ -49,10 +49,10 @@ #ifdef _KERNEL struct sd_softc { - struct device sc_dev; - struct disk sc_dk; + struct device sc_dev; + struct disk sc_dk; - int flags; + int flags; #define SDF_LOCKED 0x01 #define SDF_WANTED 0x02 #define SDF_WLABEL 0x04 /* label is writable */ @@ -60,7 +60,7 @@ struct sd_softc { #define SDF_ANCIENT 0x10 /* disk is ancient; for minphys */ #define SDF_DIRTY 0x20 /* disk is dirty; needs cache flush */ #define SDF_DYING 0x40 /* dying, when deactivated */ - struct scsi_link *sc_link; /* contains our targ, lun, etc. */ + struct scsi_link *sc_link; /* contains our targ, lun, etc. */ struct disk_parms { u_long heads; /* number of heads */ u_long cyls; /* number of cylinders */ @@ -69,11 +69,9 @@ struct sd_softc { u_long rot_rate; /* rotational rate, in RPM */ daddr64_t disksize; /* total number sectors */ } params; - struct mutex sc_buf_mtx; - struct buf sc_buf_queue; + struct buf buf_queue; void *sc_sdhook; /* our shutdown hook */ struct timeout sc_timeout; - }; #define SDGP_RESULT_OK 0 /* parameters obtained */ |