iopsp.c revision 1.2.2.6 1 /* $NetBSD: iopsp.c,v 1.2.2.6 2001/02/11 19:15:22 bouyer 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 #include <sys/lock.h>
57
58 #include <machine/bswap.h>
59 #include <machine/bus.h>
60
61 #include <dev/scsipi/scsi_all.h>
62 #include <dev/scsipi/scsi_disk.h>
63 #include <dev/scsipi/scsipi_all.h>
64 #include <dev/scsipi/scsiconf.h>
65 #include <dev/scsipi/scsi_message.h>
66
67 #include <dev/i2o/i2o.h>
68 #include <dev/i2o/iopreg.h>
69 #include <dev/i2o/iopvar.h>
70 #include <dev/i2o/iopspvar.h>
71
72 static void iopsp_attach(struct device *, struct device *, void *);
73 static void iopsp_intr(struct device *, struct iop_msg *, void *);
74 static int iopsp_ioctl(struct scsipi_channel *, u_long,
75 caddr_t, int, struct proc *);
76 static int iopsp_match(struct device *, struct cfdata *, void *);
77 static int iopsp_rescan(struct iopsp_softc *);
78 static int iopsp_reconfig(struct device *);
79 static int iopsp_scsi_abort(struct iopsp_softc *, int, struct iop_msg *);
80 static void iopsp_scsipi_request(struct scsipi_channel *,
81 scsipi_adapter_req_t, void *);
82
83 struct cfattach iopsp_ca = {
84 sizeof(struct iopsp_softc), iopsp_match, iopsp_attach
85 };
86
87 /*
88 * Match SCSI and fibre channel ports.
89 */
90 static int
91 iopsp_match(struct device *parent, struct cfdata *match, void *aux)
92 {
93 struct iop_attach_args *ia;
94 struct {
95 struct i2o_param_op_results pr;
96 struct i2o_param_read_results prr;
97 struct i2o_param_hba_ctlr_info ci;
98 } __attribute__ ((__packed__)) param;
99
100 ia = aux;
101
102 if (ia->ia_class != I2O_CLASS_BUS_ADAPTER_PORT)
103 return (0);
104
105 if (iop_param_op((struct iop_softc *)parent, ia->ia_tid, 0,
106 I2O_PARAM_HBA_CTLR_INFO, ¶m, sizeof(param)) != 0)
107 return (0);
108
109 return (param.ci.bustype == I2O_HBA_BUS_SCSI ||
110 param.ci.bustype == I2O_HBA_BUS_FCA);
111 }
112
113 /*
114 * Attach a supported device.
115 */
116 static void
117 iopsp_attach(struct device *parent, struct device *self, void *aux)
118 {
119 struct iop_attach_args *ia;
120 struct iopsp_softc *sc;
121 struct iop_softc *iop;
122 struct {
123 struct i2o_param_op_results pr;
124 struct i2o_param_read_results prr;
125 union {
126 struct i2o_param_device_identity di;
127 struct i2o_param_hba_ctlr_info ci;
128 struct i2o_param_hba_scsi_ctlr_info sci;
129 struct i2o_param_hba_scsi_port_info spi;
130 } p;
131 } __attribute__ ((__packed__)) param;
132 char ident[64];
133 int fcal, rv;
134 #ifdef I2OVERBOSE
135 int size;
136 #endif
137
138 ia = (struct iop_attach_args *)aux;
139 sc = (struct iopsp_softc *)self;
140 iop = (struct iop_softc *)parent;
141 sc->sc_tid = ia->ia_tid;
142
143 /* Register us as an initiator. */
144 sc->sc_ii.ii_dv = self;
145 sc->sc_ii.ii_intr = iopsp_intr;
146 sc->sc_ii.ii_flags = 0;
147 sc->sc_ii.ii_tid = ia->ia_tid;
148 sc->sc_ii.ii_reconfig = iopsp_reconfig;
149 if (iop_initiator_register(iop, &sc->sc_ii) != 0) {
150 printf("%s: unable to register as an initiator",
151 sc->sc_dv.dv_xname);
152 return;
153 }
154
155 rv = iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_HBA_CTLR_INFO, ¶m,
156 sizeof(param));
157 if (rv != 0) {
158 printf("%s: unable to get parameters (0x%04x; %d)\n",
159 sc->sc_dv.dv_xname, I2O_PARAM_HBA_CTLR_INFO, rv);
160 goto bad;
161 }
162
163 fcal = (param.p.ci.bustype == I2O_HBA_BUS_FCA); /* XXX */
164
165 /*
166 * Say what the device is. If we can find out what the controling
167 * device is, say what that is too.
168 */
169 printf(": %s SCSI port", fcal ? "FC-AL" : "SE/LVD");
170 if (iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_DEVICE_IDENTITY, ¶m,
171 sizeof(param)) == 0) {
172 iop_strvis(iop, param.p.di.vendorinfo,
173 sizeof(param.p.di.vendorinfo), ident, sizeof(ident));
174 printf(" <%s, ", ident);
175 iop_strvis(iop, param.p.di.productinfo,
176 sizeof(param.p.di.productinfo), ident, sizeof(ident));
177 printf("%s, ", ident);
178 iop_strvis(iop, param.p.di.revlevel,
179 sizeof(param.p.di.revlevel), ident, sizeof(ident));
180 printf("%s> ", ident);
181 }
182 printf("\n");
183
184 rv = iop_param_op(iop, ia->ia_tid, 0, I2O_PARAM_HBA_SCSI_CTLR_INFO,
185 ¶m, sizeof(param));
186 if (rv != 0) {
187 printf("%s: unable to get parameters (0x%04x; %d)\n",
188 sc->sc_dv.dv_xname, I2O_PARAM_HBA_SCSI_CTLR_INFO, rv);
189 goto bad;
190 }
191
192 #ifdef I2OVERBOSE
193 printf("%s: %d-bit, max sync rate %dMHz, initiator ID %d\n",
194 sc->sc_dv.dv_xname, param.p.sci.maxdatawidth,
195 (u_int32_t)le64toh(param.p.sci.maxsyncrate) / 1000,
196 le32toh(param.p.sci.initiatorid));
197 #endif
198
199 sc->sc_adapter.adapt_dev = &sc->sc_dv;
200 sc->sc_adapter.adapt_nchannels = 1;
201 sc->sc_adapter.adapt_openings = iop->sc_maxqueuecnt;
202 sc->sc_adapter.adapt_max_periph = iop->sc_maxqueuecnt;
203 sc->sc_adapter.adapt_ioctl = iopsp_ioctl;
204 sc->sc_adapter.adapt_minphys = minphys;
205 sc->sc_adapter.adapt_request = iopsp_scsipi_request;
206
207 memset(&sc->sc_channel, 0, sizeof(sc->sc_channel));
208 sc->sc_channel.chan_adapter = &sc->sc_adapter;
209 sc->sc_channel.chan_bustype = &scsi_bustype;
210 sc->sc_channel.chan_channel = 0;
211 sc->sc_channel.chan_ntargets = fcal ?
212 IOPSP_MAX_FCAL_TARGET : param.p.sci.maxdatawidth;
213 sc->sc_channel.chan_nluns = IOPSP_MAX_LUN;
214 sc->sc_channel.chan_id = le32toh(param.p.sci.initiatorid);
215
216 #ifdef I2OVERBOSE
217 /*
218 * Allocate the target map. Currently used for informational
219 * purposes only.
220 */
221 size = sc->sc_channel.chan_ntargets * sizeof(struct iopsp_target);
222 sc->sc_targetmap = malloc(size, M_DEVBUF, M_NOWAIT);
223 memset(sc->sc_targetmap, 0, size);
224 #endif
225
226 /* Build the two maps, and attach to scsipi. */
227 if (iopsp_reconfig(self) != 0) {
228 printf("%s: bus scan failed\n", sc->sc_dv.dv_xname);
229 goto bad;
230 }
231 config_found(self, &sc->sc_channel, scsiprint);
232 return;
233
234 bad:
235 iop_initiator_unregister(iop, &sc->sc_ii);
236 }
237
238 /*
239 * Scan the LCT to determine which devices we control, and enter them into
240 * the maps.
241 */
242 static int
243 iopsp_reconfig(struct device *dv)
244 {
245 struct iopsp_softc *sc;
246 struct iop_softc *iop;
247 struct i2o_lct_entry *le;
248 struct scsipi_channel *sc_chan;
249 struct {
250 struct i2o_param_op_results pr;
251 struct i2o_param_read_results prr;
252 struct i2o_param_scsi_device_info sdi;
253 } __attribute__ ((__packed__)) param;
254 int tid, nent, i, targ, lun, size, s, rv;
255 u_short *tidmap;
256 #ifdef I2OVERBOSE
257 struct iopsp_target *it;
258 int syncrate;
259 #endif
260
261 sc = (struct iopsp_softc *)dv;
262 iop = (struct iop_softc *)sc->sc_dv.dv_parent;
263 sc_chan = &sc->sc_channel;
264
265 /* Anything to do? */
266 if (iop->sc_lct->changeindicator == sc->sc_chgindicator)
267 return (0);
268
269 /*
270 * Allocate memory for the target/LUN -> TID map. Use zero to
271 * denote absent targets (zero is the TID of the I2O executive,
272 * and we never address that here).
273 */
274 size = sc_chan->chan_ntargets * (IOPSP_MAX_LUN) * sizeof(u_short);
275 if ((tidmap = malloc(size, M_DEVBUF, M_WAITOK)) == NULL)
276 return (ENOMEM);
277 memset(tidmap, 0, size);
278
279 #ifdef I2OVERBOSE
280 for (i = 0; i < sc_chan->chan_ntargets; i++)
281 sc->sc_targetmap[i].it_flags &= ~IT_PRESENT;
282 #endif
283
284 nent = iop->sc_nlctent;
285 for (i = 0, le = iop->sc_lct->entry; i < nent; i++, le++) {
286 switch (le16toh(le->classid) & 4095) {
287 case I2O_CLASS_SCSI_PERIPHERAL:
288 break;
289 default:
290 continue;
291 }
292 if (((le32toh(le->usertid) >> 12) & 4095) != sc->sc_tid)
293 continue;
294
295 tid = le32toh(le->localtid) & 4095;
296
297 rv = iop_param_op(iop, tid, 0, I2O_PARAM_SCSI_DEVICE_INFO,
298 ¶m, sizeof(param));
299 if (rv != 0) {
300 printf("%s: unable to get parameters (0x%04x; %d)\n",
301 sc->sc_dv.dv_xname, I2O_PARAM_SCSI_DEVICE_INFO,
302 rv);
303 continue;
304 }
305 targ = le32toh(param.sdi.identifier);
306 lun = param.sdi.luninfo[1];
307
308 /* If the device is in use by a DDM, ignore it. */
309 if ((le32toh(le->usertid) & 4095) != 4095) {
310 #ifdef I2OVERBOSE
311 if (sc->sc_tidmap == NULL ||
312 IOPSP_TIDMAP(sc->sc_tidmap, targ, lun) !=
313 IOPSP_TID_INUSE)
314 printf("%s: target %d,%d (tid %d): in use by"
315 " tid %d\n", sc->sc_dv.dv_xname,
316 targ, lun, tid,
317 le32toh(le->usertid) & 4095);
318 #endif
319 IOPSP_TIDMAP(tidmap, targ, lun) = IOPSP_TID_INUSE;
320 continue;
321 }
322 IOPSP_TIDMAP(tidmap, targ, lun) = (u_short)tid;
323
324 #ifdef I2OVERBOSE
325 /*
326 * If we've already described this target, and nothing has
327 * changed, then don't describe it again.
328 */
329 it = &sc->sc_targetmap[targ];
330 it->it_flags |= IT_PRESENT;
331 syncrate = ((int)le64toh(param.sdi.negsyncrate) + 500) / 1000;
332 if (it->it_width == param.sdi.negdatawidth &&
333 it->it_offset == param.sdi.negoffset &&
334 it->it_syncrate == syncrate)
335 continue;
336
337 it->it_width = param.sdi.negdatawidth;
338 it->it_offset = param.sdi.negoffset;
339 it->it_syncrate = syncrate;
340
341 printf("%s: target %d (tid %d): %d-bit, ", sc->sc_dv.dv_xname,
342 targ, tid, it->it_width);
343 if (it->it_syncrate == 0)
344 printf("asynchronous\n");
345 else
346 printf("synchronous at %dMHz, offset 0x%x\n",
347 it->it_syncrate, it->it_offset);
348 #endif
349 }
350
351 #ifdef I2OVERBOSE
352 for (i = 0; i < sc_chan->chan_ntargets; i++)
353 if ((sc->sc_targetmap[i].it_flags & IT_PRESENT) == 0)
354 sc->sc_targetmap[i].it_width = 0;
355 #endif
356
357 /* Swap in the new map and return. */
358 s = splbio();
359 if (sc->sc_tidmap != NULL)
360 free(sc->sc_tidmap, M_DEVBUF);
361 sc->sc_tidmap = tidmap;
362 splx(s);
363 sc->sc_chgindicator = iop->sc_lct->changeindicator;
364 return (0);
365 }
366
367 /*
368 * Re-scan the bus; to be called from a higher level (e.g. scsipi).
369 */
370 static int
371 iopsp_rescan(struct iopsp_softc *sc)
372 {
373 struct iop_softc *iop;
374 struct iop_msg *im;
375 struct i2o_hba_bus_scan *mb;
376 int rv;
377
378 iop = (struct iop_softc *)sc->sc_dv.dv_parent;
379
380 rv = lockmgr(&iop->sc_conflock, LK_EXCLUSIVE | LK_RECURSEFAIL, NULL);
381 if (rv != 0) {
382 #ifdef I2ODEBUG
383 printf("iopsp_rescan: unable to acquire lock\n");
384 #endif
385 return (rv);
386 }
387
388 /* XXX If it's boot time, the bus will already have been scanned. */
389 if (curproc != &proc0) {
390 if ((rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOINTR)) != 0)
391 goto done;
392
393 mb = (struct i2o_hba_bus_scan *)im->im_msg;
394 mb->msgflags = I2O_MSGFLAGS(i2o_hba_bus_scan);
395 mb->msgfunc = I2O_MSGFUNC(sc->sc_tid, I2O_HBA_BUS_SCAN);
396 mb->msgictx = sc->sc_ii.ii_ictx;
397 mb->msgtctx = im->im_tctx;
398
399 rv = iop_msg_enqueue(iop, im, 5*60*1000);
400 iop_msg_free(iop, &sc->sc_ii, im);
401 if (rv != 0)
402 goto done;
403
404 if ((rv = iop_lct_get(iop)) != 0)
405 goto done;
406 }
407
408 /* Rebuild the target/LUN -> TID map, release lock, and return. */
409 rv = iopsp_reconfig(&sc->sc_dv);
410 done:
411 lockmgr(&iop->sc_conflock, LK_RELEASE, NULL);
412 return (rv);
413 }
414
415 /*
416 * Start a SCSI command.
417 */
418 static void
419 iopsp_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
420 void *arg)
421 {
422 struct scsipi_xfer *xs;
423 struct scsipi_periph *periph;
424 struct iopsp_softc *sc = (void *)chan->chan_adapter->adapt_dev;
425 struct iop_msg *im;
426 struct iop_softc *iop = (struct iop_softc *)sc->sc_dv.dv_parent;
427 struct i2o_scsi_scb_exec *mb;
428 int error, flags, tid;
429
430 switch (req) {
431 case ADAPTER_REQ_RUN_XFER:
432 xs = arg;
433 periph = xs->xs_periph;
434 flags = xs->xs_control;
435
436 tid = IOPSP_TIDMAP(sc->sc_tidmap, periph->periph_target,
437 periph->periph_lun);
438 if (tid == IOPSP_TID_ABSENT || tid == IOPSP_TID_INUSE) {
439 xs->error = XS_SELTIMEOUT;
440 scsipi_done(xs);
441 return;
442 }
443
444 SC_DEBUG(periph, SDEV_DB2, ("iopsp_scsi_request run_xfer\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, 1, 10*1000) != 0) {
450 #ifdef I2ODEBUG
451 printf("%s: reset failed\n",
452 sc->sc_dv.dv_xname);
453 #endif
454 xs->error = XS_DRIVER_STUFFUP;
455 } else
456 xs->error = XS_NOERROR;
457
458 scsipi_done(xs);
459 return;
460 }
461
462 #if defined(I2ODEBUG) || defined(SCSIDEBUG)
463 if (xs->cmdlen > 16)
464 panic("%s: CDB too large\n", sc->sc_dv.dv_xname);
465 #endif
466
467 if (iop_msg_alloc(iop, &sc->sc_ii, &im,
468 (flags & (XS_CTL_POLL | XS_CTL_NOSLEEP)) != 0 ? IM_NOWAIT : 0)) {
469 xs->error = XS_RESOURCE_SHORTAGE;
470 scsipi_done(xs);
471 return;
472 }
473 im->im_dvcontext = xs;
474
475 mb = (struct i2o_scsi_scb_exec *)im->im_msg;
476 mb->msgflags = I2O_MSGFLAGS(i2o_scsi_scb_exec);
477 mb->msgfunc = I2O_MSGFUNC(tid, I2O_SCSI_SCB_EXEC);
478 mb->msgictx = sc->sc_ii.ii_ictx;
479 mb->msgtctx = im->im_tctx;
480 mb->flags = xs->cmdlen | I2O_SCB_FLAG_ENABLE_DISCONNECT |
481 I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
482 memcpy(mb->cdb, xs->cmd, xs->cmdlen);
483 mb->datalen = xs->datalen;
484
485 switch(xs->xs_tag_type) {
486 case MSG_ORDERED_Q_TAG:
487 flags |= I2O_SCB_FLAG_ORDERED_QUEUE_TAG;
488 break;
489 case MSG_SIMPLE_Q_TAG:
490 mb->flags |= I2O_SCB_FLAG_SIMPLE_QUEUE_TAG;
491 break;
492 case MSG_HEAD_OF_Q_TAG:
493 flags |= I2O_SCB_FLAG_HEAD_QUEUE_TAG;
494 break;
495 default:
496 break;
497 }
498
499 if (xs->datalen != 0) {
500 error = iop_msg_map(iop, im, xs->data, xs->datalen,
501 (flags & XS_CTL_DATA_OUT) == 0);
502 if (error) {
503 #ifdef I2ODEBUG
504 printf("%s: error %d mapping xfer\n",
505 sc->sc_dv.dv_xname, error);
506 #endif
507 xs->error = XS_DRIVER_STUFFUP;
508 iop_msg_free(iop, &sc->sc_ii, im);
509 scsipi_done(xs);
510 return;
511 }
512 if ((flags & XS_CTL_DATA_IN) == 0)
513 mb->flags |= I2O_SCB_FLAG_XFER_TO_DEVICE;
514 else
515 mb->flags |= I2O_SCB_FLAG_XFER_FROM_DEVICE;
516 }
517
518 /*
519 * If the command is allowed to execute asynchronously,
520 * enqueue it with the IOP.
521 */
522 if ((flags & XS_CTL_POLL) == 0) {
523 iop_msg_enqueue(iop, im, 0);
524 return;
525 }
526
527 if (iop_msg_send(iop, im, xs->timeout)) {
528 scsipi_printaddr(xs->xs_periph);
529 printf("timeout; aborting command\n");
530 if (iopsp_scsi_abort(sc, tid, im)) {
531 scsipi_printaddr(xs->xs_periph);
532 printf("abort failed\n");
533 }
534 xs->error = XS_TIMEOUT;
535 }
536 scsipi_done(xs);
537 return;
538 case ADAPTER_REQ_GROW_RESOURCES:
539 /* XXX Not supported. */
540 return;
541 case ADAPTER_REQ_SET_XFER_MODE:
542 /* XXX Not supported. */
543 return;
544 }
545 }
546
547 /*
548 * Abort the specified I2O_SCSI_SCB_EXEC message and its associated SCB.
549 */
550 static int
551 iopsp_scsi_abort(struct iopsp_softc *sc, int atid, struct iop_msg *aim)
552 {
553 struct iop_msg *im;
554 struct i2o_scsi_scb_abort *mb;
555 struct iop_softc *iop;
556 int rv;
557
558 iop = (struct iop_softc *)sc->sc_dv.dv_parent;
559
560 rv = iop_msg_alloc(iop, &sc->sc_ii, &im, IM_NOWAIT | IM_NOINTR);
561 if (rv != 0)
562 return (rv);
563
564 mb = (struct i2o_scsi_scb_abort *)im->im_msg;
565 mb->msgflags = I2O_MSGFLAGS(i2o_scsi_scb_abort);
566 mb->msgfunc = I2O_MSGFUNC(atid, I2O_SCSI_SCB_ABORT);
567 mb->msgictx = sc->sc_ii.ii_ictx;
568 mb->msgtctx = im->im_tctx;
569 mb->tctxabort = aim->im_tctx;
570
571 rv = iop_msg_send(iop, im, 1000);
572 iop_msg_free(iop, &sc->sc_ii, im);
573 return (rv);
574 }
575
576 /*
577 * We have a message which has been processed and replied to by the IOP -
578 * deal with it.
579 */
580 static void
581 iopsp_intr(struct device *dv, struct iop_msg *im, void *reply)
582 {
583 struct scsipi_xfer *xs;
584 struct iopsp_softc *sc;
585 struct i2o_scsi_reply *rb;
586 struct iop_softc *iop;
587 u_int hba_status, scsi_status, detail;
588 int sl;
589
590 sc = (struct iopsp_softc *)dv;
591 xs = (struct scsipi_xfer *)im->im_dvcontext;
592 iop = (struct iop_softc *)dv->dv_parent;
593
594 SC_DEBUG(xs->xs_periph, SDEV_DB2, ("iopsp_intr\n"));
595
596 if (xs->error == XS_NOERROR) {
597 rb = reply;
598 detail = le16toh(rb->detail);
599 hba_status = (detail >> 8) & 0xff;
600 scsi_status = detail & 0xff;
601
602 if (hba_status != I2O_SCSI_DSC_SUCCESS) {
603 switch (hba_status) {
604 case I2O_SCSI_DSC_ADAPTER_BUSY:
605 case I2O_SCSI_DSC_SCSI_BUS_RESET:
606 case I2O_SCSI_DSC_BUS_BUSY:
607 xs->error = XS_BUSY;
608 break;
609 case I2O_SCSI_DSC_SELECTION_TIMEOUT:
610 xs->error = XS_SELTIMEOUT;
611 break;
612 case I2O_SCSI_DSC_COMMAND_TIMEOUT:
613 case I2O_SCSI_DSC_DEVICE_NOT_PRESENT:
614 case I2O_SCSI_DSC_LUN_INVALID:
615 case I2O_SCSI_DSC_SCSI_TID_INVALID:
616 xs->error = XS_TIMEOUT;
617 break;
618 default:
619 xs->error = XS_DRIVER_STUFFUP;
620 break;
621 }
622 #ifdef I2ODEBUG
623 printf("%s: HBA status 0x%02x\n", sc->sc_dv.dv_xname,
624 hba_status);
625 #endif
626 } else if (scsi_status != SCSI_OK) {
627 switch (scsi_status) {
628 case SCSI_CHECK:
629 xs->error = XS_SENSE;
630 sl = le32toh(rb->senselen);
631 if (sl > sizeof(xs->sense.scsi_sense))
632 sl = sizeof(xs->sense.scsi_sense);
633 memcpy(&xs->sense.scsi_sense, rb->sense, sl);
634 break;
635 case SCSI_QUEUE_FULL:
636 case SCSI_BUSY:
637 xs->error = XS_BUSY;
638 break;
639 default:
640 xs->error = XS_DRIVER_STUFFUP;
641 break;
642 }
643 } else
644 xs->error = XS_NOERROR;
645
646 xs->resid = le32toh(rb->datalen) - xs->datalen;
647 xs->status = scsi_status;
648 }
649
650 /* Free the message wrapper and pass the news to scsipi. */
651 iop_msg_unmap(iop, im);
652 iop_msg_free(iop, &sc->sc_ii, im);
653 scsipi_done(xs);
654 }
655
656 /*
657 * ioctl hook; used here only to initiate low-level rescans.
658 */
659 static int
660 iopsp_ioctl(struct scsipi_channel *chan, u_long cmd, caddr_t data, int flag,
661 struct proc *p)
662 {
663 int rv;
664
665 switch (cmd) {
666 case SCBUSIOLLSCAN:
667 rv = iopsp_rescan(
668 (struct iopsp_softc *)chan->chan_adapter->adapt_dev);
669 break;
670 default:
671 rv = ENXIO;
672 break;
673 }
674
675 return (rv);
676 }
677