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