uha.c revision 1.10 1 /* $NetBSD: uha.c,v 1.10 1997/10/28 23:46:49 thorpej Exp $ */
2
3 #undef UHADEBUG
4 #ifdef DDB
5 #define integrate
6 #else
7 #define integrate static inline
8 #endif
9
10 /*-
11 * Copyright (c) 1997 The NetBSD Foundation, Inc.
12 * All rights reserved.
13 *
14 * This code is derived from software contributed to The NetBSD Foundation
15 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
16 * NASA Ames Research Center.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 * notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 * notice, this list of conditions and the following disclaimer in the
25 * documentation and/or other materials provided with the distribution.
26 * 3. All advertising materials mentioning features or use of this software
27 * must display the following acknowledgement:
28 * This product includes software developed by the NetBSD
29 * Foundation, Inc. and its contributors.
30 * 4. Neither the name of The NetBSD Foundation nor the names of its
31 * contributors may be used to endorse or promote products derived
32 * from this software without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
35 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
36 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
37 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
38 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44 * POSSIBILITY OF SUCH DAMAGE.
45 */
46
47 /*
48 * Copyright (c) 1994, 1996, 1997 Charles M. Hannum. All rights reserved.
49 *
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions
52 * are met:
53 * 1. Redistributions of source code must retain the above copyright
54 * notice, this list of conditions and the following disclaimer.
55 * 2. Redistributions in binary form must reproduce the above copyright
56 * notice, this list of conditions and the following disclaimer in the
57 * documentation and/or other materials provided with the distribution.
58 * 3. All advertising materials mentioning features or use of this software
59 * must display the following acknowledgement:
60 * This product includes software developed by Charles M. Hannum.
61 * 4. The name of the author may not be used to endorse or promote products
62 * derived from this software without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
65 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
66 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
67 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
68 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
69 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
70 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
71 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
72 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
73 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
74 */
75
76 /*
77 * Ported for use with the UltraStor 14f by Gary Close (gclose (at) wvnvms.wvnet.edu)
78 * Slight fixes to timeouts to run with the 34F
79 * Thanks to Julian Elischer for advice and help with this port.
80 *
81 * Originally written by Julian Elischer (julian (at) tfs.com)
82 * for TRW Financial Systems for use under the MACH(2.5) operating system.
83 *
84 * TRW Financial Systems, in accordance with their agreement with Carnegie
85 * Mellon University, makes this software available to CMU to distribute
86 * or use in any manner that they see fit as long as this message is kept with
87 * the software. For this reason TFS also grants any other persons or
88 * organisations permission to use or modify this software.
89 *
90 * TFS supplies this software to be publicly redistributed
91 * on the understanding that TFS is not responsible for the correct
92 * functioning of this software in any circumstances.
93 *
94 * commenced: Sun Sep 27 18:14:01 PDT 1992
95 * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993
96 */
97
98 #include <sys/types.h>
99 #include <sys/param.h>
100 #include <sys/systm.h>
101 #include <sys/kernel.h>
102 #include <sys/errno.h>
103 #include <sys/ioctl.h>
104 #include <sys/device.h>
105 #include <sys/malloc.h>
106 #include <sys/buf.h>
107 #include <sys/proc.h>
108 #include <sys/user.h>
109
110 #include <machine/bus.h>
111 #include <machine/intr.h>
112
113 #include <dev/scsipi/scsi_all.h>
114 #include <dev/scsipi/scsipi_all.h>
115 #include <dev/scsipi/scsiconf.h>
116
117 #include <dev/ic/uhareg.h>
118 #include <dev/ic/uhavar.h>
119
120 #ifndef DDB
121 #define Debugger() panic("should call debugger here (uha.c)")
122 #endif /* ! DDB */
123
124 #define UHA_MAXXFER ((UHA_NSEG - 1) << PGSHIFT)
125
126 integrate void uha_reset_mscp __P((struct uha_softc *, struct uha_mscp *));
127 void uha_free_mscp __P((struct uha_softc *, struct uha_mscp *));
128 integrate int uha_init_mscp __P((struct uha_softc *, struct uha_mscp *));
129 struct uha_mscp *uha_get_mscp __P((struct uha_softc *, int));
130 void uhaminphys __P((struct buf *));
131 int uha_scsi_cmd __P((struct scsipi_xfer *));
132 int uha_create_mscps __P((struct uha_softc *, void *, size_t));
133
134 struct scsipi_adapter uha_switch = {
135 uha_scsi_cmd,
136 uhaminphys,
137 0,
138 0,
139 };
140
141 /* the below structure is so we have a default dev struct for out link struct */
142 struct scsipi_device uha_dev = {
143 NULL, /* Use default error handler */
144 NULL, /* have a queue, served by this */
145 NULL, /* have no async handler */
146 NULL, /* Use default 'done' routine */
147 };
148
149 struct cfdriver uha_cd = {
150 NULL, "uha", DV_DULL
151 };
152
153 #define UHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
154
155 /* XXX Should put this in a better place. */
156 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
157
158 /*
159 * Attach all the sub-devices we can find
160 */
161 void
162 uha_attach(sc, upd)
163 struct uha_softc *sc;
164 struct uha_probe_data *upd;
165 {
166
167 TAILQ_INIT(&sc->sc_free_mscp);
168
169 (sc->init)(sc);
170
171 /*
172 * fill in the prototype scsipi_link.
173 */
174 sc->sc_link.scsipi_scsi.channel = SCSI_CHANNEL_ONLY_ONE;
175 sc->sc_link.adapter_softc = sc;
176 sc->sc_link.scsipi_scsi.adapter_target = upd->sc_scsi_dev;
177 sc->sc_link.adapter = &uha_switch;
178 sc->sc_link.device = &uha_dev;
179 sc->sc_link.openings = 2;
180 sc->sc_link.scsipi_scsi.max_target = 7;
181 sc->sc_link.type = BUS_SCSI;
182
183 /*
184 * ask the adapter what subunits are present
185 */
186 config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
187 }
188
189 integrate void
190 uha_reset_mscp(sc, mscp)
191 struct uha_softc *sc;
192 struct uha_mscp *mscp;
193 {
194
195 mscp->flags = 0;
196 }
197
198 /*
199 * A mscp (and hence a mbx-out) is put onto the free list.
200 */
201 void
202 uha_free_mscp(sc, mscp)
203 struct uha_softc *sc;
204 struct uha_mscp *mscp;
205 {
206 int s;
207
208 s = splbio();
209
210 uha_reset_mscp(sc, mscp);
211 TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain);
212
213 /*
214 * If there were none, wake anybody waiting for one to come free,
215 * starting with queued entries.
216 */
217 if (mscp->chain.tqe_next == 0)
218 wakeup(&sc->sc_free_mscp);
219
220 splx(s);
221 }
222
223 integrate int
224 uha_init_mscp(sc, mscp)
225 struct uha_softc *sc;
226 struct uha_mscp *mscp;
227 {
228 bus_dma_tag_t dmat = sc->sc_dmat;
229 int hashnum, error;
230
231 /*
232 * XXX Should we put a DIAGNOSTIC check for multiple
233 * XXX MSCP inits here?
234 */
235
236 bzero(mscp, sizeof(struct uha_mscp));
237
238 /*
239 * Create the DMA maps for this MSCP.
240 */
241 error = bus_dmamap_create(dmat, sizeof(struct uha_mscp), 1,
242 sizeof(struct uha_mscp), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags,
243 &mscp->dmamap_self);
244 if (error) {
245 printf("%s: can't create mscp dmamap_self\n",
246 sc->sc_dev.dv_xname);
247 return (error);
248 }
249
250 error = bus_dmamap_create(dmat, UHA_MAXXFER, UHA_NSEG, UHA_MAXXFER,
251 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags,
252 &mscp->dmamap_xfer);
253 if (error) {
254 printf("%s: can't create mscp dmamap_xfer\n",
255 sc->sc_dev.dv_xname);
256 return (error);
257 }
258
259 /*
260 * Load the permanent DMA maps.
261 */
262 error = bus_dmamap_load(dmat, mscp->dmamap_self, mscp,
263 sizeof(struct uha_mscp), NULL, BUS_DMA_NOWAIT);
264 if (error) {
265 printf("%s: can't load mscp dmamap_self\n",
266 sc->sc_dev.dv_xname);
267 bus_dmamap_destroy(dmat, mscp->dmamap_self);
268 bus_dmamap_destroy(dmat, mscp->dmamap_xfer);
269 return (error);
270 }
271
272 /*
273 * put in the phystokv hash table
274 * Never gets taken out.
275 */
276 mscp->hashkey = mscp->dmamap_self->dm_segs[0].ds_addr;
277 hashnum = MSCP_HASH(mscp->hashkey);
278 mscp->nexthash = sc->sc_mscphash[hashnum];
279 sc->sc_mscphash[hashnum] = mscp;
280 uha_reset_mscp(sc, mscp);
281 return (0);
282 }
283
284 /*
285 * Create a set of MSCPs and add them to the free list.
286 */
287 int
288 uha_create_mscps(sc, mem, size)
289 struct uha_softc *sc;
290 void *mem;
291 size_t size;
292 {
293 bus_dma_segment_t seg;
294 struct uha_mscp *mscp;
295 int rseg, error;
296
297 if (sc->sc_nummscps >= UHA_MSCP_MAX)
298 return (0);
299
300 if ((mscp = mem) != NULL)
301 goto have_mem;
302
303 size = NBPG;
304 error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg,
305 BUS_DMA_NOWAIT);
306 if (error) {
307 printf("%s: can't allocate memory for mscps\n",
308 sc->sc_dev.dv_xname);
309 return (error);
310 }
311
312 error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
313 (caddr_t *)&mscp, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC);
314 if (error) {
315 printf("%s: can't map memory for mscps\n",
316 sc->sc_dev.dv_xname);
317 bus_dmamem_free(sc->sc_dmat, &seg, rseg);
318 return (error);
319 }
320
321 have_mem:
322 bzero(mscp, size);
323 while (size > sizeof(struct uha_mscp) &&
324 sc->sc_nummscps < UHA_MSCP_MAX) {
325 error = uha_init_mscp(sc, mscp);
326 if (error) {
327 printf("%s: can't initialize mscp\n",
328 sc->sc_dev.dv_xname);
329 return (error);
330 }
331 TAILQ_INSERT_TAIL(&sc->sc_free_mscp, mscp, chain);
332 (caddr_t)mscp += ALIGN(sizeof(struct uha_mscp));
333 size -= ALIGN(sizeof(struct uha_mscp));
334 sc->sc_nummscps++;
335 }
336
337 return (0);
338 }
339
340 /*
341 * Get a free mscp
342 *
343 * If there are none, see if we can allocate a new one. If so, put it in the
344 * hash table too otherwise either return an error or sleep.
345 */
346 struct uha_mscp *
347 uha_get_mscp(sc, flags)
348 struct uha_softc *sc;
349 int flags;
350 {
351 struct uha_mscp *mscp;
352 int s;
353
354 s = splbio();
355
356 /*
357 * If we can and have to, sleep waiting for one to come free
358 * but only if we can't allocate a new one
359 */
360 for (;;) {
361 mscp = sc->sc_free_mscp.tqh_first;
362 if (mscp) {
363 TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain);
364 break;
365 }
366 if (sc->sc_nummscps < UHA_MSCP_MAX) {
367 /*
368 * uha_create_mscps() might have managed to create
369 * one before it failed. If so, don't abort,
370 * just grab it and continue to hobble along.
371 */
372 if (uha_create_mscps(sc, NULL, 0) &&
373 sc->sc_free_mscp.tqh_first == NULL) {
374 printf("%s: can't allocate mscps\n",
375 sc->sc_dev.dv_xname);
376 goto out;
377 }
378 continue;
379 }
380 if ((flags & SCSI_NOSLEEP) != 0)
381 goto out;
382 tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0);
383 }
384
385 mscp->flags |= MSCP_ALLOC;
386
387 out:
388 splx(s);
389 return (mscp);
390 }
391
392 /*
393 * given a physical address, find the mscp that it corresponds to.
394 */
395 struct uha_mscp *
396 uha_mscp_phys_kv(sc, mscp_phys)
397 struct uha_softc *sc;
398 u_long mscp_phys;
399 {
400 int hashnum = MSCP_HASH(mscp_phys);
401 struct uha_mscp *mscp = sc->sc_mscphash[hashnum];
402
403 while (mscp) {
404 if (mscp->hashkey == mscp_phys)
405 break;
406 mscp = mscp->nexthash;
407 }
408 return (mscp);
409 }
410
411 /*
412 * We have a mscp which has been processed by the adaptor, now we look to see
413 * how the operation went.
414 */
415 void
416 uha_done(sc, mscp)
417 struct uha_softc *sc;
418 struct uha_mscp *mscp;
419 {
420 bus_dma_tag_t dmat = sc->sc_dmat;
421 struct scsipi_sense_data *s1, *s2;
422 struct scsipi_xfer *xs = mscp->xs;
423
424 SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n"));
425
426 /*
427 * If we were a data transfer, unload the map that described
428 * the data buffer.
429 */
430 if (xs->datalen) {
431 bus_dmamap_sync(dmat, mscp->dmamap_xfer,
432 (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
433 BUS_DMASYNC_POSTWRITE);
434 bus_dmamap_unload(dmat, mscp->dmamap_xfer);
435 }
436
437 /*
438 * Otherwise, put the results of the operation
439 * into the xfer and call whoever started it
440 */
441 if ((mscp->flags & MSCP_ALLOC) == 0) {
442 printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
443 Debugger();
444 return;
445 }
446 if (xs->error == XS_NOERROR) {
447 if (mscp->host_stat != UHA_NO_ERR) {
448 switch (mscp->host_stat) {
449 case UHA_SBUS_TIMEOUT: /* No response */
450 xs->error = XS_SELTIMEOUT;
451 break;
452 default: /* Other scsi protocol messes */
453 printf("%s: host_stat %x\n",
454 sc->sc_dev.dv_xname, mscp->host_stat);
455 xs->error = XS_DRIVER_STUFFUP;
456 }
457 } else if (mscp->target_stat != SCSI_OK) {
458 switch (mscp->target_stat) {
459 case SCSI_CHECK:
460 s1 = &mscp->mscp_sense;
461 s2 = &xs->sense.scsi_sense;
462 *s2 = *s1;
463 xs->error = XS_SENSE;
464 break;
465 case SCSI_BUSY:
466 xs->error = XS_BUSY;
467 break;
468 default:
469 printf("%s: target_stat %x\n",
470 sc->sc_dev.dv_xname, mscp->target_stat);
471 xs->error = XS_DRIVER_STUFFUP;
472 }
473 } else
474 xs->resid = 0;
475 }
476 uha_free_mscp(sc, mscp);
477 xs->flags |= ITSDONE;
478 scsipi_done(xs);
479 }
480
481 void
482 uhaminphys(bp)
483 struct buf *bp;
484 {
485
486 if (bp->b_bcount > UHA_MAXXFER)
487 bp->b_bcount = UHA_MAXXFER;
488 minphys(bp);
489 }
490
491 /*
492 * start a scsi operation given the command and the data address. Also
493 * needs the unit, target and lu.
494 */
495 int
496 uha_scsi_cmd(xs)
497 struct scsipi_xfer *xs;
498 {
499 struct scsipi_link *sc_link = xs->sc_link;
500 struct uha_softc *sc = sc_link->adapter_softc;
501 bus_dma_tag_t dmat = sc->sc_dmat;
502 struct uha_mscp *mscp;
503 struct uha_dma_seg *sg;
504 int error, seg, flags, s;
505
506 SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n"));
507 /*
508 * get a mscp (mbox-out) to use. If the transfer
509 * is from a buf (possibly from interrupt time)
510 * then we can't allow it to sleep
511 */
512 flags = xs->flags;
513 if ((mscp = uha_get_mscp(sc, flags)) == NULL) {
514 xs->error = XS_DRIVER_STUFFUP;
515 return (TRY_AGAIN_LATER);
516 }
517 mscp->xs = xs;
518 mscp->timeout = xs->timeout;
519
520 /*
521 * Put all the arguments for the xfer in the mscp
522 */
523 if (flags & SCSI_RESET) {
524 mscp->opcode = UHA_SDR;
525 mscp->ca = 0x01;
526 } else {
527 mscp->opcode = UHA_TSP;
528 /* XXX Not for tapes. */
529 mscp->ca = 0x01;
530 bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length);
531 }
532 mscp->xdir = UHA_SDET;
533 mscp->dcn = 0x00;
534 mscp->chan = 0x00;
535 mscp->target = sc_link->scsipi_scsi.target;
536 mscp->lun = sc_link->scsipi_scsi.lun;
537 mscp->scsi_cmd_length = xs->cmdlen;
538 mscp->sense_ptr = mscp->dmamap_self->dm_segs[0].ds_addr +
539 offsetof(struct uha_mscp, mscp_sense);
540 mscp->req_sense_length = sizeof(mscp->mscp_sense);
541 mscp->host_stat = 0x00;
542 mscp->target_stat = 0x00;
543
544 if (xs->datalen) {
545 sg = mscp->uha_dma;
546 seg = 0;
547 #ifdef TFS
548 if (flags & SCSI_DATA_UIO) {
549 error = bus_dmamap_load_uio(dmat,
550 mscp->dmamap_xfer, (struct uio *)xs->data,
551 (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
552 BUS_DMA_WAITOK);
553 } else
554 #endif /*TFS */
555 {
556 error = bus_dmamap_load(dmat,
557 mscp->dmamap_xfer, xs->data, xs->datalen, NULL,
558 (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
559 BUS_DMA_WAITOK);
560 }
561
562 if (error) {
563 if (error == EFBIG) {
564 printf("%s: uha_scsi_cmd, more than %d"
565 " dma segments\n",
566 sc->sc_dev.dv_xname, UHA_NSEG);
567 } else {
568 printf("%s: uha_scsi_cmd, error %d loading"
569 " dma map\n",
570 sc->sc_dev.dv_xname, error);
571 }
572 goto bad;
573 }
574
575 bus_dmamap_sync(dmat, mscp->dmamap_xfer,
576 (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
577 BUS_DMASYNC_PREWRITE);
578
579 /*
580 * Load the hardware scatter/gather map with the
581 * contents of the DMA map.
582 */
583 for (seg = 0; seg < mscp->dmamap_xfer->dm_nsegs; seg++) {
584 mscp->uha_dma[seg].seg_addr =
585 mscp->dmamap_xfer->dm_segs[seg].ds_addr;
586 mscp->uha_dma[seg].seg_len =
587 mscp->dmamap_xfer->dm_segs[seg].ds_len;
588 }
589
590 mscp->data_addr = mscp->dmamap_self->dm_segs[0].ds_addr +
591 offsetof(struct uha_mscp, uha_dma);
592 mscp->data_length = xs->datalen;
593 mscp->sgth = 0x01;
594 mscp->sg_num = seg;
595 } else { /* No data xfer, use non S/G values */
596 mscp->data_addr = (physaddr)0;
597 mscp->data_length = 0;
598 mscp->sgth = 0x00;
599 mscp->sg_num = 0;
600 }
601 mscp->link_id = 0;
602 mscp->link_addr = (physaddr)0;
603
604 s = splbio();
605 (sc->start_mbox)(sc, mscp);
606 splx(s);
607
608 /*
609 * Usually return SUCCESSFULLY QUEUED
610 */
611 if ((flags & SCSI_POLL) == 0)
612 return (SUCCESSFULLY_QUEUED);
613
614 /*
615 * If we can't use interrupts, poll on completion
616 */
617 if ((sc->poll)(sc, xs, mscp->timeout)) {
618 uha_timeout(mscp);
619 if ((sc->poll)(sc, xs, mscp->timeout))
620 uha_timeout(mscp);
621 }
622 return (COMPLETE);
623
624 bad:
625 xs->error = XS_DRIVER_STUFFUP;
626 uha_free_mscp(sc, mscp);
627 return (COMPLETE);
628 }
629
630 void
631 uha_timeout(arg)
632 void *arg;
633 {
634 struct uha_mscp *mscp = arg;
635 struct scsipi_xfer *xs = mscp->xs;
636 struct scsipi_link *sc_link = xs->sc_link;
637 struct uha_softc *sc = sc_link->adapter_softc;
638 int s;
639
640 scsi_print_addr(sc_link);
641 printf("timed out");
642
643 s = splbio();
644
645 if (mscp->flags & MSCP_ABORT) {
646 /* abort timed out */
647 printf(" AGAIN\n");
648 /* XXX Must reset! */
649 } else {
650 /* abort the operation that has timed out */
651 printf("\n");
652 mscp->xs->error = XS_TIMEOUT;
653 mscp->timeout = UHA_ABORT_TIMEOUT;
654 mscp->flags |= MSCP_ABORT;
655 (sc->start_mbox)(sc, mscp);
656 }
657
658 splx(s);
659 }
660