Annotation of sys/dev/i2o/iopsp.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: iopsp.c,v 1.9 2006/11/28 23:59:45 dlg Exp $ */
! 2: /* $NetBSD$ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
! 6: * All rights reserved.
! 7: *
! 8: * This code is derived from software contributed to The NetBSD Foundation
! 9: * by Andrew Doran.
! 10: *
! 11: * Redistribution and use in source and binary forms, with or without
! 12: * modification, are permitted provided that the following conditions
! 13: * are met:
! 14: * 1. Redistributions of source code must retain the above copyright
! 15: * notice, this list of conditions and the following disclaimer.
! 16: * 2. Redistributions in binary form must reproduce the above copyright
! 17: * notice, this list of conditions and the following disclaimer in the
! 18: * documentation and/or other materials provided with the distribution.
! 19: * 3. All advertising materials mentioning features or use of this software
! 20: * must display the following acknowledgement:
! 21: * This product includes software developed by the NetBSD
! 22: * Foundation, Inc. and its contributors.
! 23: * 4. Neither the name of The NetBSD Foundation nor the names of its
! 24: * contributors may be used to endorse or promote products derived
! 25: * from this software without specific prior written permission.
! 26: *
! 27: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
! 28: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
! 29: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
! 30: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
! 31: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! 32: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! 33: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! 34: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! 35: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! 36: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
! 37: * POSSIBILITY OF SUCH DAMAGE.
! 38: */
! 39:
! 40: /*
! 41: * Raw SCSI device support for I2O. IOPs present SCSI devices individually;
! 42: * we group them by controlling port.
! 43: */
! 44:
! 45: #include <sys/param.h>
! 46: #include <sys/systm.h>
! 47: #include <sys/kernel.h>
! 48: #include <sys/device.h>
! 49: #include <sys/queue.h>
! 50: #include <sys/proc.h>
! 51: #include <sys/buf.h>
! 52: #include <sys/endian.h>
! 53: #include <sys/malloc.h>
! 54: #include <sys/scsiio.h>
! 55: #include <sys/lock.h>
! 56:
! 57: #include <machine/bus.h>
! 58:
! 59: #include <scsi/scsi_all.h>
! 60: #include <scsi/scsi_disk.h>
! 61: #include <scsi/scsi_all.h>
! 62: #include <scsi/scsiconf.h>
! 63: #include <scsi/scsi_message.h>
! 64:
! 65: #include <dev/i2o/i2o.h>
! 66: #include <dev/i2o/iopio.h>
! 67: #include <dev/i2o/iopvar.h>
! 68: #include <dev/i2o/iopspvar.h>
! 69:
! 70: struct cfdriver iopsp_cd = {
! 71: NULL, "iopsp", DV_DULL
! 72: };
! 73:
! 74: int iopsp_match(struct device *, void *, void *);
! 75: void iopsp_attach(struct device *, struct device *, void *);
! 76:
! 77: struct cfattach iopsp_ca = {
! 78: sizeof(struct iopsp_softc), iopsp_match, iopsp_attach
! 79: };
! 80:
! 81: int iopsp_scsi_cmd(struct scsi_xfer *);
! 82: void iopspminphys(struct buf *bp);
! 83:
! 84: struct scsi_adapter iopsp_switch = {
! 85: iopsp_scsi_cmd, iopspminphys, 0, 0,
! 86: };
! 87:
! 88: struct scsi_device iopsp_dev = {
! 89: NULL, NULL, NULL, NULL
! 90: };
! 91:
! 92: void iopsp_adjqparam(struct device *, int);
! 93: void iopsp_intr(struct device *, struct iop_msg *, void *);
! 94: int iopsp_rescan(struct iopsp_softc *);
! 95: int iopsp_reconfig(struct device *);
! 96:
! 97: /*
! 98: * Match a supported device.
! 99: */
! 100: int
! 101: iopsp_match(struct device *parent, void *match, void *aux)
! 102: {
! 103: struct iop_attach_args *ia = aux;
! 104: struct {
! 105: struct i2o_param_op_results pr;
! 106: struct i2o_param_read_results prr;
! 107: struct i2o_param_hba_ctlr_info ci;
! 108: } __attribute__ ((__packed__)) param;
! 109: int rv;
! 110:
! 111: if (ia->ia_class != I2O_CLASS_BUS_ADAPTER_PORT)
! 112: return (0);
! 113:
! 114: if ((rv = iop_param_op((struct iop_softc *)parent, ia->ia_tid, NULL, 0,
! 115: I2O_PARAM_HBA_CTLR_INFO, ¶m, sizeof(param)))) {
! 116: #ifdef I2ODEBUG
! 117: printf("iopsp_match: iop_param_op failed, status = %d\n", rv);
! 118: #endif
! 119: return (0);
! 120: }
! 121:
! 122: #ifdef I2ODEBUG
! 123: printf("iopsp_match: bustype = %d\n", param.ci.bustype);
! 124: #endif
! 125:
! 126: return (param.ci.bustype == I2O_HBA_BUS_SCSI ||
! 127: param.ci.bustype == I2O_HBA_BUS_FCA);
! 128: }
! 129:
! 130: /*
! 131: * Attach a supported device.
! 132: */
! 133: void
! 134: iopsp_attach(struct device *parent, struct device *self, void *aux)
! 135: {
! 136: struct iop_softc *iop = (struct iop_softc *)parent;
! 137: struct iopsp_softc *sc = (struct iopsp_softc *)self;
! 138: struct iop_attach_args *ia = (struct iop_attach_args *)aux;
! 139: struct scsibus_attach_args saa;
! 140: struct {
! 141: struct i2o_param_op_results pr;
! 142: struct i2o_param_read_results prr;
! 143: union {
! 144: struct i2o_param_hba_ctlr_info ci;
! 145: struct i2o_param_hba_scsi_ctlr_info sci;
! 146: struct i2o_param_hba_scsi_port_info spi;
! 147: } p;
! 148: } __attribute__ ((__packed__)) param;
! 149: int fcal, rv;
! 150: #ifdef I2OVERBOSE
! 151: int size;
! 152: #endif
! 153:
! 154: /* Register us as an initiator. */
! 155: sc->sc_ii.ii_dv = self;
! 156: sc->sc_ii.ii_intr = iopsp_intr;
! 157: sc->sc_ii.ii_flags = 0;
! 158: sc->sc_ii.ii_tid = ia->ia_tid;
! 159: sc->sc_ii.ii_reconfig = iopsp_reconfig;
! 160: sc->sc_ii.ii_adjqparam = iopsp_adjqparam;
! 161: iop_initiator_register(iop, &sc->sc_ii);
! 162:
! 163: rv = iop_param_op(iop, ia->ia_tid, NULL, 0, I2O_PARAM_HBA_CTLR_INFO,
! 164: ¶m, sizeof(param));
! 165: if (rv != 0) {
! 166: printf("%s: unable to get parameters (0x%04x; %d)\n",
! 167: sc->sc_dv.dv_xname, I2O_PARAM_HBA_CTLR_INFO, rv);
! 168: goto bad;
! 169: }
! 170:
! 171: fcal = (param.p.ci.bustype == I2O_HBA_BUS_FCA); /* XXX */
! 172:
! 173: /*
! 174: * Say what the device is. If we can find out what the controling
! 175: * device is, say what that is too.
! 176: */
! 177: printf(": SCSI port");
! 178: iop_print_ident(iop, ia->ia_tid);
! 179: printf("\n");
! 180:
! 181: rv = iop_param_op(iop, ia->ia_tid, NULL, 0,
! 182: I2O_PARAM_HBA_SCSI_CTLR_INFO, ¶m, sizeof(param));
! 183: if (rv != 0) {
! 184: printf("%s: unable to get parameters (0x%04x; %d)\n",
! 185: sc->sc_dv.dv_xname, I2O_PARAM_HBA_SCSI_CTLR_INFO, rv);
! 186: goto bad;
! 187: }
! 188:
! 189: #ifdef I2OVERBOSE
! 190: printf("%s: %d-bit, max sync rate %dMHz, initiator ID %d\n",
! 191: sc->sc_dv.dv_xname, param.p.sci.maxdatawidth,
! 192: (u_int32_t)letoh64(param.p.sci.maxsyncrate) / 1000,
! 193: letoh32(param.p.sci.initiatorid));
! 194: #endif
! 195:
! 196: sc->sc_link.adapter_softc = sc;
! 197: sc->sc_link.adapter = &iopsp_switch;
! 198: sc->sc_link.adapter_target = letoh32(param.p.sci.initiatorid);
! 199: sc->sc_link.device = &iopsp_dev;
! 200: sc->sc_link.openings = 1;
! 201: sc->sc_link.adapter_buswidth = fcal?
! 202: IOPSP_MAX_FCAL_TARGET : param.p.sci.maxdatawidth;
! 203: sc->sc_link.luns = IOPSP_MAX_LUN;
! 204:
! 205: #ifdef I2OVERBOSE
! 206: /*
! 207: * Allocate the target map. Currently used for informational
! 208: * purposes only.
! 209: */
! 210: size = sc->sc_link.adapter_buswidth * sizeof(struct iopsp_target);
! 211: sc->sc_targetmap = malloc(size, M_DEVBUF, M_NOWAIT);
! 212: bzero(sc->sc_targetmap, size);
! 213: #endif
! 214:
! 215: /* Build the two maps, and attach to scsi. */
! 216: if (iopsp_reconfig(self) != 0) {
! 217: printf("%s: configure failed\n", sc->sc_dv.dv_xname);
! 218: goto bad;
! 219: }
! 220:
! 221: bzero(&saa, sizeof(saa));
! 222: saa.saa_sc_link = &sc->sc_link;
! 223:
! 224: config_found(&sc->sc_dv, &saa, scsiprint);
! 225: return;
! 226:
! 227: bad:
! 228: iop_initiator_unregister(iop, &sc->sc_ii);
! 229: }
! 230:
! 231: /*
! 232: * Scan the LCT to determine which devices we control, and enter them into
! 233: * the maps.
! 234: */
! 235: int
! 236: iopsp_reconfig(struct device *dv)
! 237: {
! 238: struct iopsp_softc *sc = (struct iopsp_softc *)dv;
! 239: struct iop_softc *iop = (struct iop_softc *)sc->sc_dv.dv_parent;
! 240: struct i2o_lct_entry *le;
! 241: struct {
! 242: struct i2o_param_op_results pr;
! 243: struct i2o_param_read_results prr;
! 244: struct i2o_param_scsi_device_info sdi;
! 245: } __attribute__ ((__packed__)) param;
! 246: u_int tid, nent, i, targ, lun, size, s, rv, bptid;
! 247: u_short *tidmap;
! 248: #ifdef I2OVERBOSE
! 249: struct iopsp_target *it;
! 250: int syncrate;
! 251: #endif
! 252:
! 253: /* Anything to do? */
! 254: if (iop->sc_chgind == sc->sc_chgind)
! 255: return (0);
! 256:
! 257: /*
! 258: * Allocate memory for the target/LUN -> TID map. Use zero to
! 259: * denote absent targets (zero is the TID of the I2O executive,
! 260: * and we never address that here).
! 261: */
! 262: size = sc->sc_link.adapter_buswidth * IOPSP_MAX_LUN * sizeof(u_short);
! 263: if (!(tidmap = malloc(size, M_DEVBUF, M_NOWAIT)))
! 264: return (ENOMEM);
! 265: bzero(tidmap, size);
! 266:
! 267: #ifdef I2OVERBOSE
! 268: for (i = 0; i < sc->sc_link.adapter_buswidth; i++)
! 269: sc->sc_targetmap[i].it_flags &= ~IT_PRESENT;
! 270: #endif
! 271:
! 272: /*
! 273: * A quick hack to handle Intel's stacked bus port arrangement.
! 274: */
! 275: bptid = sc->sc_ii.ii_tid;
! 276: nent = iop->sc_nlctent;
! 277: for (le = iop->sc_lct->entry; nent != 0; nent--, le++)
! 278: if ((letoh16(le->classid) & 4095) ==
! 279: I2O_CLASS_BUS_ADAPTER_PORT &&
! 280: (letoh32(le->usertid) & 4095) == bptid) {
! 281: bptid = letoh16(le->localtid) & 4095;
! 282: break;
! 283: }
! 284:
! 285: nent = iop->sc_nlctent;
! 286: for (i = 0, le = iop->sc_lct->entry; i < nent; i++, le++) {
! 287: if ((letoh16(le->classid) & I2O_CLASS_MASK) !=
! 288: I2O_CLASS_SCSI_PERIPHERAL ||
! 289: ((letoh32(le->usertid) >> 12) & 4095) != bptid)
! 290: continue;
! 291: tid = letoh16(le->localtid) & I2O_LCT_ENTRY_TID_MASK;
! 292:
! 293: rv = iop_param_op(iop, tid, NULL, 0, I2O_PARAM_SCSI_DEVICE_INFO,
! 294: ¶m, sizeof(param));
! 295: if (rv != 0) {
! 296: printf("%s: unable to get parameters (0x%04x; %d)\n",
! 297: sc->sc_dv.dv_xname, I2O_PARAM_SCSI_DEVICE_INFO,
! 298: rv);
! 299: continue;
! 300: }
! 301: targ = letoh32(param.sdi.identifier);
! 302: lun = param.sdi.luninfo[1];
! 303: #if defined(DIAGNOSTIC) || defined(I2ODEBUG)
! 304: if (targ >= sc->sc_link.adapter_buswidth ||
! 305: lun >= sc->sc_link.adapter_buswidth) {
! 306: printf("%s: target %d,%d (tid %d): bad target/LUN\n",
! 307: sc->sc_dv.dv_xname, targ, lun, tid);
! 308: continue;
! 309: }
! 310: #endif
! 311:
! 312: #ifdef I2OVERBOSE
! 313: /*
! 314: * If we've already described this target, and nothing has
! 315: * changed, then don't describe it again.
! 316: */
! 317: it = &sc->sc_targetmap[targ];
! 318: it->it_flags |= IT_PRESENT;
! 319: syncrate = (int)((letoh64(param.sdi.negsyncrate) + 500) / 1000);
! 320: if (it->it_width == param.sdi.negdatawidth &&
! 321: it->it_offset == param.sdi.negoffset &&
! 322: it->it_syncrate == syncrate)
! 323: continue;
! 324:
! 325: it->it_width = param.sdi.negdatawidth;
! 326: it->it_offset = param.sdi.negoffset;
! 327: it->it_syncrate = syncrate;
! 328:
! 329: printf("%s: target %d (tid %d): %d-bit, ", sc->sc_dv.dv_xname,
! 330: targ, tid, it->it_width);
! 331: if (it->it_syncrate == 0)
! 332: printf("asynchronous\n");
! 333: else
! 334: printf("synchronous at %dMHz, offset 0x%x\n",
! 335: it->it_syncrate, it->it_offset);
! 336: #endif
! 337:
! 338: /* Ignore the device if it's in use by somebody else. */
! 339: if ((letoh32(le->usertid) & 4095) != I2O_TID_NONE) {
! 340: #ifdef I2OVERBOSE
! 341: if (sc->sc_tidmap == NULL ||
! 342: IOPSP_TIDMAP(sc->sc_tidmap, targ, lun) !=
! 343: IOPSP_TID_INUSE)
! 344: printf("%s: target %d,%d (tid %d): in use by"
! 345: " tid %d\n", sc->sc_dv.dv_xname,
! 346: targ, lun, tid,
! 347: letoh32(le->usertid) & 4095);
! 348: #endif
! 349: IOPSP_TIDMAP(tidmap, targ, lun) = IOPSP_TID_INUSE;
! 350: } else
! 351: IOPSP_TIDMAP(tidmap, targ, lun) = (u_short)tid;
! 352: }
! 353:
! 354: #ifdef I2OVERBOSE
! 355: for (i = 0; i < sc->sc_link.adapter_buswidth; i++)
! 356: if ((sc->sc_targetmap[i].it_flags & IT_PRESENT) == 0)
! 357: sc->sc_targetmap[i].it_width = 0;
! 358: #endif
! 359:
! 360: /* Swap in the new map and return. */
! 361: s = splbio();
! 362: if (sc->sc_tidmap != NULL)
! 363: free(sc->sc_tidmap, M_DEVBUF);
! 364: sc->sc_tidmap = tidmap;
! 365: splx(s);
! 366: sc->sc_chgind = iop->sc_chgind;
! 367: return (0);
! 368: }
! 369:
! 370: /*
! 371: * Re-scan the bus; to be called from a higher level (e.g. scsi).
! 372: */
! 373: int
! 374: iopsp_rescan(struct iopsp_softc *sc)
! 375: {
! 376: struct iop_softc *iop;
! 377: struct iop_msg *im;
! 378: struct i2o_hba_bus_scan mf;
! 379: int rv;
! 380:
! 381: iop = (struct iop_softc *)sc->sc_dv.dv_parent;
! 382:
! 383: rv = lockmgr(&iop->sc_conflock, LK_EXCLUSIVE, NULL);
! 384: if (rv != 0) {
! 385: #ifdef I2ODEBUG
! 386: printf("iopsp_rescan: unable to acquire lock\n");
! 387: #endif
! 388: return (rv);
! 389: }
! 390:
! 391: im = iop_msg_alloc(iop, &sc->sc_ii, IM_WAIT);
! 392:
! 393: mf.msgflags = I2O_MSGFLAGS(i2o_hba_bus_scan);
! 394: mf.msgfunc = I2O_MSGFUNC(sc->sc_ii.ii_tid, I2O_HBA_BUS_SCAN);
! 395: mf.msgictx = sc->sc_ii.ii_ictx;
! 396: mf.msgtctx = im->im_tctx;
! 397:
! 398: rv = iop_msg_post(iop, im, &mf, 5*60*1000);
! 399: iop_msg_free(iop, im);
! 400: if (rv != 0)
! 401: printf("%s: bus rescan failed (error %d)\n",
! 402: sc->sc_dv.dv_xname, rv);
! 403:
! 404: if ((rv = iop_lct_get(iop)) == 0)
! 405: rv = iopsp_reconfig(&sc->sc_dv);
! 406:
! 407: lockmgr(&iop->sc_conflock, LK_RELEASE, NULL);
! 408: return (rv);
! 409: }
! 410:
! 411: void
! 412: iopspminphys(bp)
! 413: struct buf *bp;
! 414: {
! 415: if (bp->b_bcount > IOP_MAX_XFER)
! 416: bp->b_bcount = IOP_MAX_XFER;
! 417: minphys(bp);
! 418: }
! 419:
! 420: /*
! 421: * Start a SCSI command.
! 422: */
! 423: int
! 424: iopsp_scsi_cmd(xs)
! 425: struct scsi_xfer *xs;
! 426: {
! 427: struct scsi_link *link = xs->sc_link;
! 428: struct iopsp_softc *sc = (struct iopsp_softc *)link->adapter_softc;
! 429: struct iop_softc *iop = (struct iop_softc *)sc->sc_dv.dv_parent;
! 430: struct iop_msg *im;
! 431: struct i2o_scsi_scb_exec *mf;
! 432: int error, tid, s;
! 433: u_int32_t mb[IOP_MAX_MSG_SIZE / sizeof(u_int32_t)];
! 434:
! 435: tid = IOPSP_TIDMAP(sc->sc_tidmap, link->target, link->lun);
! 436: if (tid == IOPSP_TID_ABSENT || tid == IOPSP_TID_INUSE) {
! 437: xs->error = XS_SELTIMEOUT;
! 438: scsi_done(xs);
! 439: return (COMPLETE);
! 440: }
! 441:
! 442: SC_DEBUG(xs->sc_link, SDEV_DB2, ("iopsp_scsi_cmd: run_xfer\n"));
! 443:
! 444: /* Need to reset the target? */
! 445: if ((xs->flags & XS_RESET) != 0) {
! 446: if (iop_simple_cmd(iop, tid, I2O_SCSI_DEVICE_RESET,
! 447: sc->sc_ii.ii_ictx, 1, 30*1000) != 0) {
! 448: #ifdef I2ODEBUG
! 449: printf("%s: reset failed\n",
! 450: sc->sc_dv.dv_xname);
! 451: #endif
! 452: xs->error = XS_DRIVER_STUFFUP;
! 453: } else
! 454: xs->error = XS_NOERROR;
! 455:
! 456: scsi_done(xs);
! 457: return (COMPLETE);
! 458: }
! 459:
! 460: #if defined(I2ODEBUG) || defined(SCSIDEBUG)
! 461: if (xs->cmdlen > sizeof(mf->cdb))
! 462: panic("%s: CDB too large", sc->sc_dv.dv_xname);
! 463: #endif
! 464:
! 465: im = iop_msg_alloc(iop, &sc->sc_ii, IM_POLL_INTR |
! 466: IM_NOSTATUS | ((xs->flags & SCSI_POLL) != 0 ? IM_POLL : 0));
! 467: im->im_dvcontext = xs;
! 468:
! 469: mf = (struct i2o_scsi_scb_exec *)mb;
! 470: mf->msgflags = I2O_MSGFLAGS(i2o_scsi_scb_exec);
! 471: mf->msgfunc = I2O_MSGFUNC(tid, I2O_SCSI_SCB_EXEC);
! 472: mf->msgictx = sc->sc_ii.ii_ictx;
! 473: mf->msgtctx = im->im_tctx;
! 474: mf->flags = xs->cmdlen | I2O_SCB_FLAG_ENABLE_DISCONNECT |
! 475: I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
! 476: mf->datalen = xs->datalen;
! 477: memcpy(mf->cdb, xs->cmd, xs->cmdlen);
! 478:
! 479: #if 0
! 480: switch (xs->xs_tag_type) {
! 481: case MSG_ORDERED_Q_TAG:
! 482: mf->flags |= I2O_SCB_FLAG_ORDERED_QUEUE_TAG;
! 483: break;
! 484: case MSG_SIMPLE_Q_TAG:
! 485: mf->flags |= I2O_SCB_FLAG_SIMPLE_QUEUE_TAG;
! 486: break;
! 487: case MSG_HEAD_OF_Q_TAG:
! 488: mf->flags |= I2O_SCB_FLAG_HEAD_QUEUE_TAG;
! 489: break;
! 490: default:
! 491: break;
! 492: }
! 493: #endif
! 494:
! 495: if (xs->datalen != 0) {
! 496: error = iop_msg_map_bio(iop, im, mb, xs->data,
! 497: xs->datalen, (xs->flags & SCSI_DATA_OUT) == 0);
! 498: if (error) {
! 499: xs->error = XS_DRIVER_STUFFUP;
! 500: iop_msg_free(iop, im);
! 501: scsi_done(xs);
! 502: return (COMPLETE);
! 503: }
! 504: if ((xs->flags & SCSI_DATA_IN) == 0)
! 505: mf->flags |= I2O_SCB_FLAG_XFER_TO_DEVICE;
! 506: else
! 507: mf->flags |= I2O_SCB_FLAG_XFER_FROM_DEVICE;
! 508: }
! 509:
! 510: s = splbio();
! 511: sc->sc_curqd++;
! 512: splx(s);
! 513:
! 514: if (iop_msg_post(iop, im, mb, xs->timeout)) {
! 515: s = splbio();
! 516: sc->sc_curqd--;
! 517: splx(s);
! 518: if (xs->datalen != 0)
! 519: iop_msg_unmap(iop, im);
! 520: iop_msg_free(iop, im);
! 521: xs->error = XS_DRIVER_STUFFUP;
! 522: scsi_done(xs);
! 523: return (COMPLETE);
! 524: }
! 525:
! 526: return (xs->flags & SCSI_POLL? COMPLETE : SUCCESSFULLY_QUEUED);
! 527: }
! 528:
! 529: #ifdef notyet
! 530: /*
! 531: * Abort the specified I2O_SCSI_SCB_EXEC message and its associated SCB.
! 532: */
! 533: int
! 534: iopsp_scsi_abort(struct iopsp_softc *sc, int atid, struct iop_msg *aim)
! 535: {
! 536: struct iop_msg *im;
! 537: struct i2o_scsi_scb_abort mf;
! 538: struct iop_softc *iop;
! 539: int rv, s;
! 540:
! 541: iop = (struct iop_softc *)sc->sc_dv.dv_parent;
! 542: im = iop_msg_alloc(iop, &sc->sc_ii, IM_POLL);
! 543:
! 544: mf.msgflags = I2O_MSGFLAGS(i2o_scsi_scb_abort);
! 545: mf.msgfunc = I2O_MSGFUNC(atid, I2O_SCSI_SCB_ABORT);
! 546: mf.msgictx = sc->sc_ii.ii_ictx;
! 547: mf.msgtctx = im->im_tctx;
! 548: mf.tctxabort = aim->im_tctx;
! 549:
! 550: s = splbio();
! 551: rv = iop_msg_post(iop, im, &mf, 30000);
! 552: splx(s);
! 553: iop_msg_free(iop, im);
! 554: return (rv);
! 555: }
! 556: #endif
! 557:
! 558: /*
! 559: * We have a message which has been processed and replied to by the IOP -
! 560: * deal with it.
! 561: */
! 562: void
! 563: iopsp_intr(struct device *dv, struct iop_msg *im, void *reply)
! 564: {
! 565: struct scsi_xfer *xs;
! 566: struct iopsp_softc *sc;
! 567: struct i2o_scsi_reply *rb;
! 568: struct iop_softc *iop;
! 569: u_int sl;
! 570:
! 571: sc = (struct iopsp_softc *)dv;
! 572: xs = (struct scsi_xfer *)im->im_dvcontext;
! 573: iop = (struct iop_softc *)dv->dv_parent;
! 574: rb = reply;
! 575:
! 576: SC_DEBUG(xs->sc_link, SDEV_DB2, ("iopsp_intr\n"));
! 577:
! 578: if ((rb->msgflags & I2O_MSGFLAGS_FAIL) != 0) {
! 579: xs->error = XS_DRIVER_STUFFUP;
! 580: xs->resid = xs->datalen;
! 581: } else {
! 582: if (rb->hbastatus != I2O_SCSI_DSC_SUCCESS) {
! 583: switch (rb->hbastatus) {
! 584: case I2O_SCSI_DSC_ADAPTER_BUSY:
! 585: case I2O_SCSI_DSC_SCSI_BUS_RESET:
! 586: case I2O_SCSI_DSC_BUS_BUSY:
! 587: xs->error = XS_BUSY;
! 588: break;
! 589: case I2O_SCSI_DSC_SELECTION_TIMEOUT:
! 590: xs->error = XS_SELTIMEOUT;
! 591: break;
! 592: case I2O_SCSI_DSC_COMMAND_TIMEOUT:
! 593: case I2O_SCSI_DSC_DEVICE_NOT_PRESENT:
! 594: case I2O_SCSI_DSC_LUN_INVALID:
! 595: case I2O_SCSI_DSC_SCSI_TID_INVALID:
! 596: xs->error = XS_TIMEOUT;
! 597: break;
! 598: default:
! 599: xs->error = XS_DRIVER_STUFFUP;
! 600: break;
! 601: }
! 602: printf("%s: HBA status 0x%02x\n", sc->sc_dv.dv_xname,
! 603: rb->hbastatus);
! 604: } else if (rb->scsistatus != SCSI_OK) {
! 605: switch (rb->scsistatus) {
! 606: case SCSI_CHECK:
! 607: xs->error = XS_SENSE;
! 608: sl = letoh32(rb->senselen);
! 609: if (sl > sizeof(xs->sense))
! 610: sl = sizeof(xs->sense);
! 611: bcopy(rb->sense, &xs->sense, sl);
! 612: break;
! 613: case SCSI_QUEUE_FULL:
! 614: case SCSI_BUSY:
! 615: xs->error = XS_BUSY;
! 616: break;
! 617: default:
! 618: xs->error = XS_DRIVER_STUFFUP;
! 619: break;
! 620: }
! 621: } else
! 622: xs->error = XS_NOERROR;
! 623:
! 624: xs->resid = xs->datalen - letoh32(rb->datalen);
! 625: xs->status = rb->scsistatus;
! 626: }
! 627:
! 628: /* Free the message wrapper and pass the news to scsi. */
! 629: if (xs->datalen != 0)
! 630: iop_msg_unmap(iop, im);
! 631: iop_msg_free(iop, im);
! 632:
! 633: if (--sc->sc_curqd == sc->sc_link.openings)
! 634: wakeup(&sc->sc_curqd);
! 635:
! 636: scsi_done(xs);
! 637: }
! 638:
! 639: /*
! 640: * The number of openings available to us has changed, so inform scsi.
! 641: */
! 642: void
! 643: iopsp_adjqparam(struct device *dv, int mpi)
! 644: {
! 645: struct iopsp_softc *sc = (struct iopsp_softc *)dv;
! 646: int s;
! 647:
! 648: s = splbio();
! 649: sc->sc_link.openings = mpi;
! 650: if (mpi < sc->sc_curqd)
! 651: tsleep(&sc->sc_curqd, PWAIT, "iopspdrn", 0);
! 652: splx(s);
! 653: }
CVSweb