diff options
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 | 461 | ||||
-rw-r--r-- | sys/scsi/scsi_ioctl.c | 301 | ||||
-rw-r--r-- | sys/scsi/scsiconf.c | 229 | ||||
-rw-r--r-- | sys/scsi/scsiconf.h | 50 | ||||
-rw-r--r-- | sys/scsi/sd.c | 459 | ||||
-rw-r--r-- | sys/scsi/sdvar.h | 15 |
8 files changed, 721 insertions, 895 deletions
diff --git a/sys/dev/ic/mpi.c b/sys/dev/ic/mpi.c index 0137a8dee4b..a08fddef6cd 100644 --- a/sys/dev/ic/mpi.c +++ b/sys/dev/ic/mpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpi.c,v 1.121 2009/11/12 06:20:27 dlg Exp $ */ +/* $OpenBSD: mpi.c,v 1.122 2009/12/01 01:40:02 dlg Exp $ */ /* * Copyright (c) 2005, 2006, 2009 David Gwynne <dlg@openbsd.org> @@ -2176,7 +2176,6 @@ 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; @@ -2214,7 +2213,6 @@ 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 4bccf1c9d43..342763ed552 100644 --- a/sys/scsi/mpath.c +++ b/sys/scsi/mpath.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mpath.c,v 1.10 2009/11/12 06:20:27 dlg Exp $ */ +/* $OpenBSD: mpath.c,v 1.11 2009/12/01 01:40:02 dlg 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,6 +78,8 @@ 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, @@ -136,9 +138,13 @@ mpath_xs_stuffup(struct scsi_xfer *xs) int mpath_probe(struct scsi_link *link) { - if (link->lun != 0 || mpath_nodes[link->target] == NULL) + struct mpath_node *n = mpath_nodes[link->target]; + + if (link->lun != 0 || n == NULL) return (ENXIO); + link->id = devid_copy(n->node_id); + return (0); } @@ -148,36 +154,53 @@ 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); - int rv; - int s; + struct scsi_xfer *mxs; if (n == NULL || p == NULL) { mpath_xs_stuffup(xs); return (COMPLETE); } - 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))); + 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; - 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; - } + 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; + + memcpy(&xs->sense, &mxs->sense, sizeof(xs->sense)); + + scsi_xs_put(mxs); s = splbio(); scsi_done(xs); splx(s); - - return (COMPLETE); } void @@ -205,14 +228,14 @@ mpath_path_attach(struct scsi_link *link) return (ENODEV); /* XXX this is dumb. should check inq shizz */ - if (link->id.d_type == DEVID_NONE) + if (ISSET(link->flags, SDEV_VIRTUAL) || link->id == NULL) 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; @@ -229,13 +252,18 @@ 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.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); + n->node_id = devid_copy(link->id); 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); @@ -260,7 +288,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; @@ -279,3 +307,16 @@ 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 55d695f6c4e..f844d955881 100644 --- a/sys/scsi/scsi_base.c +++ b/sys/scsi/scsi_base.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_base.c,v 1.143 2009/11/22 20:09:53 krw Exp $ */ +/* $OpenBSD: scsi_base.c,v 1.144 2009/12/01 01:40:02 dlg Exp $ */ /* $NetBSD: scsi_base.c,v 1.43 1997/04/02 02:29:36 mycroft Exp $ */ /* @@ -50,15 +50,14 @@ #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 @@ -95,6 +94,7 @@ 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,42 +183,43 @@ scsi_deinit() */ struct scsi_xfer * -scsi_get_xs(struct scsi_link *sc_link, int flags) +scsi_xs_get(struct scsi_link *link, int flags) { - struct scsi_xfer *xs; - int s; - - SC_DEBUG(sc_link, SDEV_DB3, ("scsi_get_xs\n")); + struct scsi_xfer *xs; - 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); + mtx_enter(&link->mtx); + while (link->openings == 0) { + if (ISSET(flags, SCSI_NOSLEEP)) { + mtx_leave(&link->mtx); return (NULL); } + + SET(link->flags, SDEV_WAITING); + msleep(link, &link->mtx, PRIBIO, "getxs", 0); } - SC_DEBUG(sc_link, SDEV_DB3, ("calling pool_get\n")); + link->openings--; + mtx_leave(&link->mtx); + + /* pool is shared, link mtx is not */ xs = pool_get(&scsi_xfer_pool, - ((flags & SCSI_NOSLEEP) != 0 ? PR_NOWAIT : PR_WAITOK)); - if (xs != NULL) { - bzero(xs, sizeof(*xs)); - sc_link->openings--; - xs->flags = flags; + ISSET(flags, SCSI_NOSLEEP) ? PR_NOWAIT : PR_WAITOK); + if (xs == NULL) { + mtx_enter(&link->mtx); + link->openings++; + mtx_leave(&link->mtx); } else { - sc_print_addr(sc_link); - printf("cannot allocate scsi xs\n"); + 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; } - splx(s); - - SC_DEBUG(sc_link, SDEV_DB3, ("returning\n")); return (xs); } @@ -229,75 +230,21 @@ scsi_get_xs(struct scsi_link *sc_link, int flags) * If another process is waiting for an xs, do a wakeup, let it proceed */ void -scsi_free_xs(struct scsi_xfer *xs, int start) +scsi_xs_put(struct scsi_xfer *xs) { - struct scsi_link *sc_link = xs->sc_link; - - splassert(IPL_BIO); - - SC_DEBUG(sc_link, SDEV_DB3, ("scsi_free_xs\n")); + struct scsi_link *link = xs->sc_link; pool_put(&scsi_xfer_pool, xs); - sc_link->openings++; + + mtx_enter(&link->mtx); + link->openings++; /* If someone is waiting for scsi_xfer, wake them up. */ - 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); + if (ISSET(link->flags, SDEV_WAITING)) { + CLR(link->flags, SDEV_WAITING); + wakeup(link); } -} - -/* - * 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); + mtx_leave(&link->mtx); } /* @@ -759,171 +706,52 @@ 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_done(struct scsi_xfer *xs) +scsi_xs_exec(struct scsi_xfer *xs) { - struct scsi_link *sc_link = xs->sc_link; - struct buf *bp; - int error; - - SC_DEBUG(sc_link, SDEV_DB2, ("scsi_done\n")); + int rv; + int s; - splassert(IPL_BIO); - - xs->flags |= ITSDONE; + xs->flags &= ~ITSDONE; + xs->error = XS_NOERROR; + xs->resid = xs->datalen; + xs->status = 0; /* - * 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; - } + * scsi_xs_exec() guarantees that scsi_done() will be called on the xs + * it was given. The adapter is responsible for calling scsi_done() + * except if its scsi_cmd() routine returns NO_CCB or TRY_AGAIN_LATER. + * In those cases we must call scsi_done() for it. + */ - if (!((xs->flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP)) { + rv = xs->sc_link->adapter->scsi_cmd(xs); + if (rv == NO_CCB) { /* - * 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 + * Give the xs back to the device driver to retry on its own. */ - wakeup(xs); - return; + + xs->error = XS_NO_CCB; + s = splbio(); + scsi_done(xs); + splx(s); } /* - * Go and handle errors now. - * If it returns ERESTART then we should RETRY + * The adapter has called or will call scsi_done(). */ -retry: - error = sc_err1(xs); - if (error == ERESTART) { - switch ((*(sc_link->adapter->scsi_cmd)) (xs)) { - case SUCCESSFULLY_QUEUED: - return; - - 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) +/* + * This routine is called by the adapter when its xs handling is done. + */ +void +scsi_done(struct scsi_xfer *xs) { - int error, flags, rslt, s; - - xs->flags &= ~ITSDONE; - xs->error = XS_NOERROR; - xs->resid = xs->datalen; - xs->status = 0; - - /* - * Do the transfer. If we are polling we will return: - * COMPLETE. - * - * if under full steam (interrupts) it will return: - * SUCCESSFULLY_QUEUED, will do a wakeup when complete. - * 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. - */ - - 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(); - /* 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); - /* FALLTHROUGH */ - case COMPLETE: /* Polling command completed ok */ - if ((flags & (SCSI_NOSLEEP | SCSI_POLL)) == SCSI_NOSLEEP) - return (EJUSTRETURN); - if (xs->bp) - return (EJUSTRETURN); - SC_DEBUG(xs->sc_link, SDEV_DB3, ("back in cmd()\n")); - if ((error = sc_err1(xs)) != ERESTART) - return (error); - goto retry; - - case NO_CCB: - return (EAGAIN); + splassert(IPL_BIO); - default: - panic("scsi_execute_xs: invalid return code (%#x)", rslt); - } + xs->flags |= ITSDONE; -#ifdef DIAGNOSTIC - panic("scsi_execute_xs: impossible"); -#endif - return (EINVAL); + xs->done(xs); } /* @@ -933,54 +761,83 @@ retry: * to associate with the transfer, we need that too. */ int -scsi_scsi_cmd(struct scsi_link *sc_link, struct scsi_generic *scsi_cmd, +scsi_scsi_cmd(struct scsi_link *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; - - SC_DEBUG(sc_link, SDEV_DB2, ("scsi_cmd\n")); + struct scsi_xfer *xs; + int error; + int s; #ifdef DIAGNOSTIC if (bp != NULL && (flags & SCSI_NOSLEEP) == 0) panic("scsi_scsi_cmd: buffer without nosleep"); #endif - if ((xs = scsi_make_xs(sc_link, scsi_cmd, cmdlen, data_addr, datalen, - retries, timeout, bp, flags)) == NULL) + xs = scsi_xs_get(link, flags); + if (xs == NULL) return (ENOMEM); -#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 */ - - error = scsi_execute_xs(xs); + memcpy(xs->cmd, scsi_cmd, cmdlen); + xs->cmdlen = cmdlen; + xs->data = data_addr; + xs->datalen = datalen; + xs->retries = retries; + xs->timeout = timeout; -#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 */ + xs->done = scsi_xs_done; - if (error == EJUSTRETURN) - return (0); + 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); + } - s = splbio(); + error = sc_err1(xs); + } while (error == ERESTART); + + if (error != EAGAIN) { + 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; + } + + s = splbio(); + biodone(bp); + splx(s); + } - if (error == EAGAIN) - scsi_free_xs(xs, 0); /* Don't restart queue. */ - else - scsi_free_xs(xs, 1); + 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); + } + } - splx(s); + scsi_xs_put(xs); 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) { @@ -1041,6 +898,10 @@ sc_err1(struct scsi_xfer *xs) error = EIO; break; + case XS_NO_CCB: + error = EAGAIN; + break; + default: sc_print_addr(xs->sc_link); printf("unknown error category (0x%x) from scsi driver\n", @@ -1100,10 +961,6 @@ 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. @@ -1996,57 +1853,3 @@ 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 2b4d79d2532..bda32e3516b 100644 --- a/sys/scsi/scsi_ioctl.c +++ b/sys/scsi/scsi_ioctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsi_ioctl.c,v 1.37 2009/11/12 06:20:27 dlg Exp $ */ +/* $OpenBSD: scsi_ioctl.c,v 1.38 2009/12/01 01:40:02 dlg Exp $ */ /* $NetBSD: scsi_ioctl.c,v 1.23 1996/10/12 23:23:17 christos Exp $ */ /* @@ -52,22 +52,7 @@ #include <scsi/scsiconf.h> #include <sys/scsiio.h> -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 *); +int scsi_ioc_cmd(struct scsi_link *, scsireq_t *); const unsigned char scsi_readsafe_cmd[256] = { [0x00] = 1, /* TEST UNIT READY */ @@ -110,237 +95,98 @@ const unsigned char scsi_readsafe_cmd[256] = { [0xbe] = 1 /* READ CD */ }; -struct scsi_ioctl * -si_get(void) +int +scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq) { - struct scsi_ioctl *si; - int s; + struct scsi_xfer *xs; + int err = 0; + int s; - si = malloc(sizeof(*si), M_TEMP, M_WAITOK | M_ZERO); - s = splbio(); - LIST_INSERT_HEAD(&si_head, si, si_list); - splx(s); - return (si); -} + if (screq->cmdlen > sizeof(struct scsi_generic)) + return (EFAULT); -void -si_free(struct scsi_ioctl *si) -{ - int s; + xs = scsi_xs_get(link, 0); + if (xs == NULL) + return (ENOMEM); - 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; + memcpy(xs->cmd, screq->cmd, screq->cmdlen); + xs->cmdlen = screq->cmdlen; - s = splbio(); - LIST_FOREACH(si, &si_head, si_list) { - if (bp == &si->si_bp) - break; + if (screq->datalen > 0) { + xs->data = malloc(screq->datalen, M_TEMP, M_WAITOK); + xs->datalen = screq->datalen; } - splx(s); - return (si); -} - -/* - * 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; - - splassert(IPL_BIO); + 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; + } - 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; + xs->flags |= SCSI_DATA_OUT; } - si = si_find(bp); - if (si == NULL) { - sc_print_addr(xs->sc_link); - printf("User command with no ioctl\n"); - return; - } + xs->timeout = screq->timeout; + xs->retries = 0; /* user must do the retries *//* ignored */ - screq = &si->si_screq; - sc_link = si->si_sc_link; - SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n")); + xs->done = (void (*)(struct scsi_xfer *))wakeup; + + scsi_xs_exec(xs); + s = splbio(); + while (!ISSET(xs->flags, ITSDONE)) + tsleep(xs, PRIBIO, "scsiioc", 0); + splx(s); 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: - 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->senselen_used = min(sizeof(xs->sense), + sizeof(screq->sense)); + bcopy(&xs->sense, screq->sense, screq->senselen_used); screq->retsts = SCCMD_SENSE; break; case XS_SHORTSENSE: - 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); + printf("XS_SHORTSENSE\n"); + screq->senselen_used = min(sizeof(xs->sense), + sizeof(screq->sense)); + bcopy(&xs->sense, screq->sense, screq->senselen_used); 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; } - 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; + if (screq->datalen > 0 && screq->flags & SCCMD_READ) { + err = copyout(xs->data, screq->databuf, screq->datalen); + if (err != 0) + goto err; } - 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; - } +err: + if (screq->datalen > 0) + free(xs->data, M_TEMP); + scsi_xs_put(xs); - sc_link = si->si_sc_link; - (*sc_link->adapter->scsi_minphys)(bp, sc_link); + return (err); } /* @@ -354,8 +200,6 @@ 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) { @@ -378,7 +222,6 @@ 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; @@ -391,41 +234,8 @@ scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr, } switch(cmd) { - 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 SCIOCCOMMAND: + return (scsi_ioc_cmd(sc_link, (scsireq_t *)addr)); case SCIOCDEBUG: { int level = *((int *)addr); @@ -441,11 +251,6 @@ 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 58d0f609d22..c2dbd8c4cbd 100644 --- a/sys/scsi/scsiconf.c +++ b/sys/scsi/scsiconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.c,v 1.151 2009/11/12 06:20:27 dlg Exp $ */ +/* $OpenBSD: scsiconf.c,v 1.152 2009/12/01 01:40:02 dlg Exp $ */ /* $NetBSD: scsiconf.c,v 1.57 1996/05/02 01:09:01 neil Exp $ */ /* @@ -113,6 +113,10 @@ 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. */ @@ -199,30 +203,99 @@ scsibusattach(struct device *parent, struct device *self, void *aux) int scsibusactivate(struct device *dev, int act) { - return (config_activate_children(dev, 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; + } } int scsibusdetach(struct device *dev, int type) { struct scsibus_softc *sb = (struct scsibus_softc *)dev; - int i, j, error; + int i, error; #if NBIO > 0 bio_unregister(&sb->sc_dev); #endif - if ((error = config_detach_children(dev, type)) != 0) + error = scsi_detach_bus(sb, type); + if (error != 0) return (error); for (i = 0; i < sb->sc_buswidth; i++) { - 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); - } + if (sb->sc_link[i] != NULL) free(sb->sc_link[i], M_DEVBUF); - } } free(sb->sc_link, M_DEVBUF); @@ -274,6 +347,9 @@ 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); @@ -379,19 +455,22 @@ int scsi_detach_bus(struct scsibus_softc *sc, int flags) { struct scsi_link *alink = sc->adapter_link; - int i; + int i, err, rv = 0; - for (i = 0; i < alink->adapter_buswidth; i++) - scsi_detach_target(sc, i, flags); + for (i = 0; i < alink->adapter_buswidth; i++) { + err = scsi_detach_target(sc, i, flags); + if (err != 0 && err != ENXIO) + rv = err; + } - return (0); + return (rv); } int scsi_detach_target(struct scsibus_softc *sc, int target, int flags) { struct scsi_link *alink = sc->adapter_link; - int i, err, rv = 0, detached = 0; + int i, err, rv = 0; if (target < 0 || target >= alink->adapter_buswidth || target == alink->adapter_target) @@ -405,12 +484,11 @@ scsi_detach_target(struct scsibus_softc *sc, int target, int flags) continue; err = scsi_detach_lun(sc, target, i, flags); - if (err != 0) + if (err != 0 && err != ENXIO) rv = err; - detached = 1; } - return (detached ? rv : ENXIO); + return (rv); } int @@ -453,6 +531,8 @@ 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; @@ -685,6 +765,42 @@ 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 */ } /* @@ -738,6 +854,7 @@ 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")); @@ -810,15 +927,15 @@ scsi_probedev(struct scsibus_softc *scsi, int target, int lun) ; else if (sc_link->flags & SDEV_UMASS) ; - else if (sc_link->id.d_type != DEVID_NONE && - !DEVID_CMP(&scsi->sc_link[target][0]->id, &sc_link->id)) + else if (sc_link->id != NULL && + !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 bad; + goto free_devid; } #if NMPATH > 0 @@ -872,7 +989,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 bad; + goto free_devid; } /* @@ -909,6 +1026,9 @@ 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); @@ -979,6 +1099,9 @@ 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) @@ -1008,9 +1131,10 @@ int scsi_devid_pg83(struct scsi_link *link) { struct scsi_vpd_hdr hdr; - struct scsi_vpd_devid_hdr dhdr; + struct scsi_vpd_devid_hdr dhdr, chdr; u_int8_t *pg, *id; - int type, idtype = 0, idlen; + int type, idtype = 0; + u_char idflags; int len, pos; int rv; @@ -1048,7 +1172,8 @@ scsi_devid_pg83(struct scsi_link *link) case VPD_DEVID_TYPE_T10: if (type >= idtype) { idtype = type; - idlen = dhdr.len; + + chdr = dhdr; id = &pg[pos]; } break; @@ -1063,21 +1188,27 @@ scsi_devid_pg83(struct scsi_link *link) } while (idtype != VPD_DEVID_TYPE_NAA && len != pos); if (idtype > 0) { - link->id.d_id = malloc(idlen, M_DEVBUF, M_WAITOK); - - switch (idtype) { + switch (VPD_DEVID_TYPE(chdr.flags)) { case VPD_DEVID_TYPE_NAA: - link->id.d_type = DEVID_NAA; + idtype = DEVID_NAA; break; case VPD_DEVID_TYPE_EUI64: - link->id.d_type = DEVID_EUI; + idtype = DEVID_EUI; break; case VPD_DEVID_TYPE_T10: - link->id.d_type = DEVID_T10; + idtype = DEVID_T10; break; } - link->id.d_len = idlen; - memcpy(link->id.d_id, id, idlen); + 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); } else rv = ENODEV; @@ -1095,3 +1226,35 @@ 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 1d896e3e4ad..8f9619d8fb9 100644 --- a/sys/scsi/scsiconf.h +++ b/sys/scsi/scsiconf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: scsiconf.h,v 1.111 2009/11/22 20:16:43 krw Exp $ */ +/* $OpenBSD: scsiconf.h,v 1.112 2009/12/01 01:40:02 dlg Exp $ */ /* $NetBSD: scsiconf.h,v 1.35 1997/04/02 02:29:38 mycroft Exp $ */ /* @@ -53,6 +53,7 @@ #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> @@ -234,20 +235,31 @@ _4ltol(u_int8_t *bytes) #define DEVID_T10 3 struct devid { - int d_type; - u_int d_len; - u_int8_t *d_id; + 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. + */ }; -#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 \ +#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)) \ ) +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: @@ -337,7 +349,6 @@ 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 */ @@ -366,7 +377,8 @@ 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 devid *id; + struct mutex mtx; }; int scsiprint(void *, const char *); @@ -442,6 +454,8 @@ struct scsi_xfer { * timeout structure for hba's to use for a command */ struct timeout stimeout; + void *cookie; + void (*done)(struct scsi_xfer *); }; /* @@ -484,6 +498,7 @@ struct scsi_xfer { #define XS_BUSY 5 /* The device busy, try again later? */ #define XS_SHORTSENSE 6 /* Check the ATAPI sense for the error */ #define XS_RESET 8 /* bus was reset; possible retry command */ +#define XS_NO_CCB 9 /* device should requeue io and retry */ /* * Possible retries for scsi_test_unit_ready() @@ -555,14 +570,23 @@ 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 baf354d80b0..081733da095 100644 --- a/sys/scsi/sd.c +++ b/sys/scsi/sd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sd.c,v 1.164 2009/11/12 06:20:27 dlg Exp $ */ +/* $OpenBSD: sd.c,v 1.165 2009/12/01 01:40:02 dlg Exp $ */ /* $NetBSD: sd.c,v 1.111 1997/04/02 02:29:41 mycroft Exp $ */ /*- @@ -83,10 +83,7 @@ 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); @@ -96,6 +93,16 @@ 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 @@ -111,7 +118,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 */ - sddone, /* deal with stats at interrupt time */ + NULL, /* have no done handler */ }; const struct scsi_inquiry_pattern sd_patterns[] = { @@ -163,6 +170,8 @@ 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 */ @@ -197,7 +206,7 @@ sdattach(struct device *parent, struct device *self, void *aux) */ printf("\n"); - timeout_set(&sd->sc_timeout, sdrestart, sd); + timeout_set(&sd->sc_timeout, sdstart, sd); /* Spin up non-UMASS devices ready or not. */ if ((sd->sc_link->flags & SDEV_UMASS) == 0) @@ -551,12 +560,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 */ - disksort(&sd->buf_queue, bp); + mtx_enter(&sd->sc_buf_mtx); + disksort(&sd->sc_buf_queue, bp); + mtx_leave(&sd->sc_buf_mtx); /* * Tell the device to get going on the transfer if it's @@ -564,8 +573,6 @@ sdstrategy(struct buf *bp) */ sdstart(sd); - splx(s); - device_unref(&sd->sc_dev); return; @@ -583,6 +590,77 @@ 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, @@ -595,62 +673,33 @@ done: * 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 *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; + struct sd_softc *sc = (struct sd_softc *)v; + struct scsi_link *link = sc->sc_link; + struct scsi_xfer *xs; + struct buf *bp; daddr64_t blkno; - int nblks, cmdlen, error; + int nblks; + int read; struct partition *p; - if (sd->flags & SDF_DYING) + if (sc->flags & SDF_DYING) return; SC_DEBUG(sc_link, SDEV_DB2, ("sdstart\n")); - 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; - + CLR(sc->flags, SDF_WAITING); + while (!ISSET(sc->flags, SDF_WAITING) && + (bp = sd_buf_dequeue(sc)) != NULL) { /* * If the device has become invalid, abort all the * reads and writes until all files have been closed and * re-opened */ - if ((sc_link->flags & SDEV_MEDIA_LOADED) == 0) { + if ((link->flags & SDEV_MEDIA_LOADED) == 0) { bp->b_error = EIO; bp->b_flags |= B_ERROR; bp->b_resid = bp->b_bcount; @@ -658,129 +707,86 @@ sdstart(void *v) continue; } - /* - * 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. - */ + xs = scsi_xs_get(link, SCSI_NOSLEEP); + if (xs == NULL) { + sd_buf_requeue(sc, bp); + return; + } + blkno = - bp->b_blkno / (sd->sc_dk.dk_label->d_secsize / DEV_BSIZE); - p = &sd->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; + bp->b_blkno / (sc->sc_dk.dk_label->d_secsize / DEV_BSIZE); + p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; blkno += DL_GETPOFFSET(p); - nblks = howmany(bp->b_bcount, sd->sc_dk.dk_label->d_secsize); + nblks = howmany(bp->b_bcount, sc->sc_dk.dk_label->d_secsize); + read = bp->b_flags & B_READ; /* * Fill out the scsi command. If the transfer will * fit in a "small" cdb, use it. */ - if (!(sc_link->flags & SDEV_ATAPI) && - !(sc_link->quirks & SDEV_ONLYBIG) && + if (!(link->flags & SDEV_ATAPI) && + !(link->quirks & SDEV_ONLYBIG) && ((blkno & 0x1fffff) == blkno) && - ((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; - } + ((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); - /* Instrumentation. */ - disk_busy(&sd->sc_dk); + xs->flags |= (read ? SCSI_DATA_IN : SCSI_DATA_OUT); + xs->timeout = 60000; + xs->data = bp->b_data; + xs->datalen = bp->b_bcount; - /* - * 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; - } + xs->done = sd_buf_done; + xs->cookie = bp; + + /* Instrumentation. */ + disk_busy(&sc->sc_dk); + scsi_xs_exec(xs); } } void -sdrestart(void *v) +sd_buf_done(struct scsi_xfer *xs) { - int s; + struct sd_softc *sc = xs->sc_link->device_softc; + struct buf *bp = xs->cookie; - s = splbio(); - sdstart(v); - splx(s); -} + splassert(IPL_BIO); -void -sddone(struct scsi_xfer *xs) -{ - struct sd_softc *sd = xs->sc_link->device_softc; + disk_unbusy(&sc->sc_dk, bp->b_bcount - xs->resid, + bp->b_flags & B_READ); + + switch (xs->error) { + case XS_NOERROR: + bp->b_error = 0; + bp->b_resid = xs->resid; + break; - if (xs->bp != NULL) - disk_unbusy(&sd->sc_dk, (xs->bp->b_bcount - xs->bp->b_resid), - (xs->bp->b_flags & B_READ)); + case XS_NO_CCB: + /* The hardware is busy, requeue the buf and try it later. */ + sd_buf_requeue(sc, bp); + scsi_xs_put(xs); + SET(sc->flags, SDF_WAITING); /* break out of sdstart loop */ + timeout_add(&sc->sc_timeout, 1); + return; + + default: + bp->b_error = EIO; + bp->b_flags |= B_ERROR; + bp->b_resid = bp->b_bcount; + break; + } + + biodone(bp); + scsi_xs_put(xs); + sdstart(sc); /* restart io */ } void @@ -1081,27 +1087,6 @@ 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 @@ -1186,7 +1171,6 @@ sdsize(dev_t dev) } /* #define SD_DUMP_NOT_TRUSTED if you just want to watch */ -static struct scsi_xfer sx; static int sddoingadump; /* @@ -1196,7 +1180,7 @@ static int sddoingadump; int sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) { - struct sd_softc *sd; /* disk unit to do the I/O */ + struct sd_softc *sc; /* disk unit to do the I/O */ struct disklabel *lp; /* disk's disklabel */ int unit, part; int sectorsize; /* size of a disk sector */ @@ -1204,9 +1188,7 @@ 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) @@ -1219,7 +1201,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 || (sd = sd_cd.cd_devs[unit]) == NULL) + if (unit >= sd_cd.cd_ndevs || (sc = sd_cd.cd_devs[unit]) == NULL) return ENXIO; /* @@ -1229,12 +1211,12 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) */ #if 0 /* Make sure it was initialized. */ - if ((sd->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED) + if ((sc->sc_link->flags & SDEV_MEDIA_LOADED) != SDEV_MEDIA_LOADED) return ENXIO; #endif /* Convert to disk sectors. Request must be a multiple of size. */ - lp = sd->sc_dk.dk_label; + lp = sc->sc_dk.dk_label; sectorsize = lp->d_secsize; if ((size % sectorsize) != 0) return EFAULT; @@ -1251,43 +1233,25 @@ 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 - /* - * 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 = 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; xs->data = va; xs->datalen = nwrt * sectorsize; - /* - * Pass all this info to the scsi driver. - */ - retval = (*(sd->sc_link->adapter->scsi_cmd)) (xs); - if (retval != COMPLETE) - return ENXIO; + sd_cmd_rw10(xs, 0, blkno, nwrt); /* XXX */ + + scsi_xs_exec(xs); + if (xs->error != XS_NOERROR) + return (ENXIO); + scsi_xs_put(xs); #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); @@ -1299,8 +1263,10 @@ sddump(dev_t dev, daddr64_t blkno, caddr_t va, size_t size) blkno += nwrt; va += sectorsize * nwrt; } + sddoingadump = 0; - return 0; + + return (0); } /* @@ -1469,14 +1435,17 @@ validate: return (SDGP_RESULT_OK); } +void +sd_flush_done(struct scsi_xfer *xs); void -sd_flush(struct sd_softc *sd, int flags) +sd_flush(struct sd_softc *sc, int flags) { - struct scsi_link *sc_link = sd->sc_link; - struct scsi_synchronize_cache cmd; + struct scsi_link *link = sc->sc_link; + struct scsi_xfer *xs; + struct scsi_synchronize_cache *cmd; - if (sc_link->quirks & SDEV_NOSYNCCACHE) + if (link->quirks & SDEV_NOSYNCCACHE) return; /* @@ -1485,15 +1454,40 @@ sd_flush(struct sd_softc *sd, int flags) * that the command is not supported by the device. */ - 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)) { + 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; + + do { + scsi_xs_exec(xs); + if (!ISSET(xs->flags, SCSI_POLL)) { + while (!ISSET(xs->flags, ITSDONE)) + tsleep(xs, PRIBIO, "sdflush", 0); + } + } while (xs->status == XS_NO_CCB); + + if (xs->error != XS_NOERROR) SC_DEBUG(sc_link, SDEV_DB1, ("cache sync failed\n")); - } else - sd->flags &= ~SDF_DIRTY; + 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); } /* @@ -1502,16 +1496,11 @@ sd_flush(struct sd_softc *sd, int flags) void sd_kill_buffers(struct sd_softc *sd) { - struct buf *dp, *bp; - int s; - - s = splbio(); - for (dp = &sd->buf_queue; (bp = dp->b_actf) != NULL; ) { - dp->b_actf = bp->b_actf; + struct buf *bp; + 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 7147b6f6f0e..d9b8d2837a6 100644 --- a/sys/scsi/sdvar.h +++ b/sys/scsi/sdvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: sdvar.h,v 1.23 2009/11/12 06:20:27 dlg Exp $ */ +/* $OpenBSD: sdvar.h,v 1.24 2009/12/01 01:40:02 dlg 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,8 @@ 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. */ +#define SDF_WAITING 0x80 /* bus is busy, try again later */ + 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,9 +70,11 @@ struct sd_softc { u_long rot_rate; /* rotational rate, in RPM */ daddr64_t disksize; /* total number sectors */ } params; - struct buf buf_queue; + struct mutex sc_buf_mtx; + struct buf sc_buf_queue; void *sc_sdhook; /* our shutdown hook */ struct timeout sc_timeout; + }; #define SDGP_RESULT_OK 0 /* parameters obtained */ |