Annotation of sys/dev/i2o/iopsp.c, Revision 1.1.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