xref: /netbsd-src/sys/dev/ic/uha.c (revision fdecd6a253f999ae92b139670d9e15cc9df4497c)
1 /*	$NetBSD: uha.c,v 1.8 1997/06/06 23:31:05 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@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@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 <scsi/scsi_all.h>
114 #include <scsi/scsiconf.h>
115 
116 #include <dev/ic/uhareg.h>
117 #include <dev/ic/uhavar.h>
118 
119 #ifndef	DDB
120 #define Debugger() panic("should call debugger here (uha.c)")
121 #endif /* ! DDB */
122 
123 #define	UHA_MAXXFER	((UHA_NSEG - 1) << PGSHIFT)
124 
125 integrate void uha_reset_mscp __P((struct uha_softc *, struct uha_mscp *));
126 void uha_free_mscp __P((struct uha_softc *, struct uha_mscp *));
127 integrate void uha_init_mscp __P((struct uha_softc *, struct uha_mscp *));
128 struct uha_mscp *uha_get_mscp __P((struct uha_softc *, int));
129 void uhaminphys __P((struct buf *));
130 int uha_scsi_cmd __P((struct scsi_xfer *));
131 int uha_create_mscps __P((struct uha_softc *, void *, size_t));
132 
133 struct scsi_adapter uha_switch = {
134 	uha_scsi_cmd,
135 	uhaminphys,
136 	0,
137 	0,
138 };
139 
140 /* the below structure is so we have a default dev struct for out link struct */
141 struct scsi_device uha_dev = {
142 	NULL,			/* Use default error handler */
143 	NULL,			/* have a queue, served by this */
144 	NULL,			/* have no async handler */
145 	NULL,			/* Use default 'done' routine */
146 };
147 
148 struct cfdriver uha_cd = {
149 	NULL, "uha", DV_DULL
150 };
151 
152 #define	UHA_ABORT_TIMEOUT	2000	/* time to wait for abort (mSec) */
153 
154 /* XXX Should put this in a better place. */
155 #define	offsetof(type, member)	((size_t)(&((type *)0)->member))
156 
157 /*
158  * Attach all the sub-devices we can find
159  */
160 void
161 uha_attach(sc, upd)
162 	struct uha_softc *sc;
163 	struct uha_probe_data *upd;
164 {
165 
166 	TAILQ_INIT(&sc->sc_free_mscp);
167 
168 	(sc->init)(sc);
169 
170 	/*
171 	 * fill in the prototype scsi_link.
172 	 */
173 	sc->sc_link.channel = SCSI_CHANNEL_ONLY_ONE;
174 	sc->sc_link.adapter_softc = sc;
175 	sc->sc_link.adapter_target = upd->sc_scsi_dev;
176 	sc->sc_link.adapter = &uha_switch;
177 	sc->sc_link.device = &uha_dev;
178 	sc->sc_link.openings = 2;
179 	sc->sc_link.max_target = 7;
180 
181 	/*
182 	 * ask the adapter what subunits are present
183 	 */
184 	config_found(&sc->sc_dev, &sc->sc_link, scsiprint);
185 }
186 
187 integrate void
188 uha_reset_mscp(sc, mscp)
189 	struct uha_softc *sc;
190 	struct uha_mscp *mscp;
191 {
192 
193 	mscp->flags = 0;
194 }
195 
196 /*
197  * A mscp (and hence a mbx-out) is put onto the free list.
198  */
199 void
200 uha_free_mscp(sc, mscp)
201 	struct uha_softc *sc;
202 	struct uha_mscp *mscp;
203 {
204 	int s;
205 
206 	s = splbio();
207 
208 	uha_reset_mscp(sc, mscp);
209 	TAILQ_INSERT_HEAD(&sc->sc_free_mscp, mscp, chain);
210 
211 	/*
212 	 * If there were none, wake anybody waiting for one to come free,
213 	 * starting with queued entries.
214 	 */
215 	if (mscp->chain.tqe_next == 0)
216 		wakeup(&sc->sc_free_mscp);
217 
218 	splx(s);
219 }
220 
221 integrate void
222 uha_init_mscp(sc, mscp)
223 	struct uha_softc *sc;
224 	struct uha_mscp *mscp;
225 {
226 	bus_dma_tag_t dmat = sc->sc_dmat;
227 	int hashnum;
228 
229 	/*
230 	 * XXX Should we put a DIAGNOSTIC check for multiple
231 	 * XXX MSCP inits here?
232 	 */
233 
234 	bzero(mscp, sizeof(struct uha_mscp));
235 
236 	/*
237 	 * Create the DMA maps for this MSCP.
238 	 */
239 	if (bus_dmamap_create(dmat, sizeof(struct uha_mscp), 1,
240 	    sizeof(struct uha_mscp), 0, BUS_DMA_NOWAIT | sc->sc_dmaflags,
241 	    &mscp->dmamap_self) ||
242 
243 					/* XXX What's a good value for this? */
244 	    bus_dmamap_create(dmat, UHA_MAXXFER, UHA_NSEG, UHA_MAXXFER,
245 	    0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW | sc->sc_dmaflags,
246 	    &mscp->dmamap_xfer))
247 		panic("uha_init_mscp: can't create DMA maps");
248 
249 	/*
250 	 * Load the permanent DMA maps.
251 	 */
252 	if (bus_dmamap_load(dmat, mscp->dmamap_self, mscp,
253 	    sizeof(struct uha_mscp), NULL, BUS_DMA_NOWAIT))
254 		panic("uha_init_mscp: can't load permanent maps");
255 
256 	/*
257 	 * put in the phystokv hash table
258 	 * Never gets taken out.
259 	 */
260 	mscp->hashkey = mscp->dmamap_self->dm_segs[0].ds_addr;
261 	hashnum = MSCP_HASH(mscp->hashkey);
262 	mscp->nexthash = sc->sc_mscphash[hashnum];
263 	sc->sc_mscphash[hashnum] = mscp;
264 	uha_reset_mscp(sc, mscp);
265 }
266 
267 /*
268  * Create a set of MSCPs and add them to the free list.
269  */
270 int
271 uha_create_mscps(sc, mem, size)
272 	struct uha_softc *sc;
273 	void *mem;
274 	size_t size;
275 {
276 	bus_dma_segment_t seg;
277 	struct uha_mscp *mscp;
278 	int rseg, error;
279 
280 	if (sc->sc_nummscps >= UHA_MSCP_MAX)
281 		return (0);
282 
283 	if ((mscp = mem) != NULL)
284 		goto have_mem;
285 
286 	size = NBPG;
287 	error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, 0, &seg, 1, &rseg,
288 	    BUS_DMA_NOWAIT);
289 	if (error)
290 		return (error);
291 
292 	error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size,
293 	    (caddr_t *)&mscp, BUS_DMA_NOWAIT|BUS_DMAMEM_NOSYNC);
294 	if (error) {
295 		bus_dmamem_free(sc->sc_dmat, &seg, rseg);
296 		return (error);
297 	}
298 
299  have_mem:
300 	bzero(mscp, size);
301 	while (size > sizeof(struct uha_mscp)) {
302 		uha_init_mscp(sc, mscp);
303 		sc->sc_nummscps++;
304 		TAILQ_INSERT_TAIL(&sc->sc_free_mscp, mscp, chain);
305 		(caddr_t)mscp += ALIGN(sizeof(struct uha_mscp));
306 		size -= ALIGN(sizeof(struct uha_mscp));
307 		if (sc->sc_nummscps >= UHA_MSCP_MAX)
308 			break;
309 	}
310 
311 	return (0);
312 }
313 
314 /*
315  * Get a free mscp
316  *
317  * If there are none, see if we can allocate a new one.  If so, put it in the
318  * hash table too otherwise either return an error or sleep.
319  */
320 struct uha_mscp *
321 uha_get_mscp(sc, flags)
322 	struct uha_softc *sc;
323 	int flags;
324 {
325 	struct uha_mscp *mscp;
326 	int s;
327 
328 	s = splbio();
329 
330 	/*
331 	 * If we can and have to, sleep waiting for one to come free
332 	 * but only if we can't allocate a new one
333 	 */
334 	for (;;) {
335 		mscp = sc->sc_free_mscp.tqh_first;
336 		if (mscp) {
337 			TAILQ_REMOVE(&sc->sc_free_mscp, mscp, chain);
338 			break;
339 		}
340 		if (sc->sc_nummscps < UHA_MSCP_MAX) {
341 			if (uha_create_mscps(sc, NULL, 0)) {
342 				printf("%s: can't allocate mscps\n",
343 				    sc->sc_dev.dv_xname);
344 				goto out;
345 			}
346 			continue;
347 		}
348 		if ((flags & SCSI_NOSLEEP) != 0)
349 			goto out;
350 		tsleep(&sc->sc_free_mscp, PRIBIO, "uhamsc", 0);
351 	}
352 
353 	mscp->flags |= MSCP_ALLOC;
354 
355 out:
356 	splx(s);
357 	return (mscp);
358 }
359 
360 /*
361  * given a physical address, find the mscp that it corresponds to.
362  */
363 struct uha_mscp *
364 uha_mscp_phys_kv(sc, mscp_phys)
365 	struct uha_softc *sc;
366 	u_long mscp_phys;
367 {
368 	int hashnum = MSCP_HASH(mscp_phys);
369 	struct uha_mscp *mscp = sc->sc_mscphash[hashnum];
370 
371 	while (mscp) {
372 		if (mscp->hashkey == mscp_phys)
373 			break;
374 		mscp = mscp->nexthash;
375 	}
376 	return (mscp);
377 }
378 
379 /*
380  * We have a mscp which has been processed by the adaptor, now we look to see
381  * how the operation went.
382  */
383 void
384 uha_done(sc, mscp)
385 	struct uha_softc *sc;
386 	struct uha_mscp *mscp;
387 {
388 	bus_dma_tag_t dmat = sc->sc_dmat;
389 	struct scsi_sense_data *s1, *s2;
390 	struct scsi_xfer *xs = mscp->xs;
391 
392 	SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n"));
393 
394 	/*
395 	 * If we were a data transfer, unload the map that described
396 	 * the data buffer.
397 	 */
398 	if (xs->datalen) {
399 		bus_dmamap_sync(dmat, mscp->dmamap_xfer,
400 		    (xs->flags & SCSI_DATA_IN) ? BUS_DMASYNC_POSTREAD :
401 		    BUS_DMASYNC_POSTWRITE);
402 		bus_dmamap_unload(dmat, mscp->dmamap_xfer);
403 	}
404 
405 	/*
406 	 * Otherwise, put the results of the operation
407 	 * into the xfer and call whoever started it
408 	 */
409 	if ((mscp->flags & MSCP_ALLOC) == 0) {
410 		printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
411 		Debugger();
412 		return;
413 	}
414 	if (xs->error == XS_NOERROR) {
415 		if (mscp->host_stat != UHA_NO_ERR) {
416 			switch (mscp->host_stat) {
417 			case UHA_SBUS_TIMEOUT:		/* No response */
418 				xs->error = XS_SELTIMEOUT;
419 				break;
420 			default:	/* Other scsi protocol messes */
421 				printf("%s: host_stat %x\n",
422 				    sc->sc_dev.dv_xname, mscp->host_stat);
423 				xs->error = XS_DRIVER_STUFFUP;
424 			}
425 		} else if (mscp->target_stat != SCSI_OK) {
426 			switch (mscp->target_stat) {
427 			case SCSI_CHECK:
428 				s1 = &mscp->mscp_sense;
429 				s2 = &xs->sense;
430 				*s2 = *s1;
431 				xs->error = XS_SENSE;
432 				break;
433 			case SCSI_BUSY:
434 				xs->error = XS_BUSY;
435 				break;
436 			default:
437 				printf("%s: target_stat %x\n",
438 				    sc->sc_dev.dv_xname, mscp->target_stat);
439 				xs->error = XS_DRIVER_STUFFUP;
440 			}
441 		} else
442 			xs->resid = 0;
443 	}
444 	uha_free_mscp(sc, mscp);
445 	xs->flags |= ITSDONE;
446 	scsi_done(xs);
447 }
448 
449 void
450 uhaminphys(bp)
451 	struct buf *bp;
452 {
453 
454 	if (bp->b_bcount > UHA_MAXXFER)
455 		bp->b_bcount = UHA_MAXXFER;
456 	minphys(bp);
457 }
458 
459 /*
460  * start a scsi operation given the command and the data address.  Also
461  * needs the unit, target and lu.
462  */
463 int
464 uha_scsi_cmd(xs)
465 	struct scsi_xfer *xs;
466 {
467 	struct scsi_link *sc_link = xs->sc_link;
468 	struct uha_softc *sc = sc_link->adapter_softc;
469 	bus_dma_tag_t dmat = sc->sc_dmat;
470 	struct uha_mscp *mscp;
471 	struct uha_dma_seg *sg;
472 	int error, seg, flags, s;
473 
474 	SC_DEBUG(sc_link, SDEV_DB2, ("uha_scsi_cmd\n"));
475 	/*
476 	 * get a mscp (mbox-out) to use. If the transfer
477 	 * is from a buf (possibly from interrupt time)
478 	 * then we can't allow it to sleep
479 	 */
480 	flags = xs->flags;
481 	if ((mscp = uha_get_mscp(sc, flags)) == NULL) {
482 		xs->error = XS_DRIVER_STUFFUP;
483 		return (TRY_AGAIN_LATER);
484 	}
485 	mscp->xs = xs;
486 	mscp->timeout = xs->timeout;
487 
488 	/*
489 	 * Put all the arguments for the xfer in the mscp
490 	 */
491 	if (flags & SCSI_RESET) {
492 		mscp->opcode = UHA_SDR;
493 		mscp->ca = 0x01;
494 	} else {
495 		mscp->opcode = UHA_TSP;
496 		/* XXX Not for tapes. */
497 		mscp->ca = 0x01;
498 		bcopy(xs->cmd, &mscp->scsi_cmd, mscp->scsi_cmd_length);
499 	}
500 	mscp->xdir = UHA_SDET;
501 	mscp->dcn = 0x00;
502 	mscp->chan = 0x00;
503 	mscp->target = sc_link->target;
504 	mscp->lun = sc_link->lun;
505 	mscp->scsi_cmd_length = xs->cmdlen;
506 	mscp->sense_ptr = mscp->dmamap_self->dm_segs[0].ds_addr +
507 	    offsetof(struct uha_mscp, mscp_sense);
508 	mscp->req_sense_length = sizeof(mscp->mscp_sense);
509 	mscp->host_stat = 0x00;
510 	mscp->target_stat = 0x00;
511 
512 	if (xs->datalen) {
513 		sg = mscp->uha_dma;
514 		seg = 0;
515 #ifdef	TFS
516 		if (flags & SCSI_DATA_UIO) {
517 			error = bus_dmamap_load_uio(dmat,
518 			    mscp->dmamap_xfer, (struct uio *)xs->data,
519 			    (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
520 			    BUS_DMA_WAITOK);
521 		} else
522 #endif /*TFS */
523 		{
524 			error = bus_dmamap_load(dmat,
525 			    mscp->dmamap_xfer, xs->data, xs->datalen, NULL,
526 			    (flags & SCSI_NOSLEEP) ? BUS_DMA_NOWAIT :
527 			    BUS_DMA_WAITOK);
528 		}
529 
530 		if (error) {
531 			if (error == EFBIG) {
532 				printf("%s: uha_scsi_cmd, more than %d"
533 				    " dma segments\n",
534 				    sc->sc_dev.dv_xname, UHA_NSEG);
535 			} else {
536 				printf("%s: uha_scsi_cmd, error %d loading"
537 				    " dma map\n",
538 				    sc->sc_dev.dv_xname, error);
539 			}
540 			goto bad;
541 		}
542 
543 		bus_dmamap_sync(dmat, mscp->dmamap_xfer,
544 		    (flags & SCSI_DATA_IN) ? BUS_DMASYNC_PREREAD :
545 		    BUS_DMASYNC_PREWRITE);
546 
547 		/*
548 		 * Load the hardware scatter/gather map with the
549 		 * contents of the DMA map.
550 		 */
551 		for (seg = 0; seg < mscp->dmamap_xfer->dm_nsegs; seg++) {
552 			mscp->uha_dma[seg].seg_addr =
553 			    mscp->dmamap_xfer->dm_segs[seg].ds_addr;
554 			mscp->uha_dma[seg].seg_len =
555 			    mscp->dmamap_xfer->dm_segs[seg].ds_len;
556 		}
557 
558 		mscp->data_addr = mscp->dmamap_self->dm_segs[0].ds_addr +
559 		    offsetof(struct uha_mscp, uha_dma);
560 		mscp->data_length = xs->datalen;
561 		mscp->sgth = 0x01;
562 		mscp->sg_num = seg;
563 	} else {		/* No data xfer, use non S/G values */
564 		mscp->data_addr = (physaddr)0;
565 		mscp->data_length = 0;
566 		mscp->sgth = 0x00;
567 		mscp->sg_num = 0;
568 	}
569 	mscp->link_id = 0;
570 	mscp->link_addr = (physaddr)0;
571 
572 	s = splbio();
573 	(sc->start_mbox)(sc, mscp);
574 	splx(s);
575 
576 	/*
577 	 * Usually return SUCCESSFULLY QUEUED
578 	 */
579 	if ((flags & SCSI_POLL) == 0)
580 		return (SUCCESSFULLY_QUEUED);
581 
582 	/*
583 	 * If we can't use interrupts, poll on completion
584 	 */
585 	if ((sc->poll)(sc, xs, mscp->timeout)) {
586 		uha_timeout(mscp);
587 		if ((sc->poll)(sc, xs, mscp->timeout))
588 			uha_timeout(mscp);
589 	}
590 	return (COMPLETE);
591 
592 bad:
593 	xs->error = XS_DRIVER_STUFFUP;
594 	uha_free_mscp(sc, mscp);
595 	return (COMPLETE);
596 }
597 
598 void
599 uha_timeout(arg)
600 	void *arg;
601 {
602 	struct uha_mscp *mscp = arg;
603 	struct scsi_xfer *xs = mscp->xs;
604 	struct scsi_link *sc_link = xs->sc_link;
605 	struct uha_softc *sc = sc_link->adapter_softc;
606 	int s;
607 
608 	sc_print_addr(sc_link);
609 	printf("timed out");
610 
611 	s = splbio();
612 
613 	if (mscp->flags & MSCP_ABORT) {
614 		/* abort timed out */
615 		printf(" AGAIN\n");
616 		/* XXX Must reset! */
617 	} else {
618 		/* abort the operation that has timed out */
619 		printf("\n");
620 		mscp->xs->error = XS_TIMEOUT;
621 		mscp->timeout = UHA_ABORT_TIMEOUT;
622 		mscp->flags |= MSCP_ABORT;
623 		(sc->start_mbox)(sc, mscp);
624 	}
625 
626 	splx(s);
627 }
628