FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/aha.c
1 /* $NetBSD: aha.c,v 1.43 2003/11/02 11:07:44 wiz Exp $ */
2
3 /*-
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9 * Simulation Facility, NASA Ames Research Center.
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 * Originally written by Julian Elischer (julian@tfs.com)
42 * for TRW Financial Systems for use under the MACH(2.5) operating system.
43 *
44 * TRW Financial Systems, in accordance with their agreement with Carnegie
45 * Mellon University, makes this software available to CMU to distribute
46 * or use in any manner that they see fit as long as this message is kept with
47 * the software. For this reason TFS also grants any other persons or
48 * organisations permission to use or modify this software.
49 *
50 * TFS supplies this software to be publicly redistributed
51 * on the understanding that TFS is not responsible for the correct
52 * functioning of this software in any circumstances.
53 */
54
55 #include <sys/cdefs.h>
56 __KERNEL_RCSID(0, "$NetBSD: aha.c,v 1.43 2003/11/02 11:07:44 wiz Exp $");
57
58 #include "opt_ddb.h"
59
60 #undef AHADIAG
61 #ifdef DDB
62 #define integrate
63 #else
64 #define integrate static inline
65 #endif
66
67 #include <sys/param.h>
68 #include <sys/systm.h>
69 #include <sys/callout.h>
70 #include <sys/kernel.h>
71 #include <sys/errno.h>
72 #include <sys/ioctl.h>
73 #include <sys/device.h>
74 #include <sys/malloc.h>
75 #include <sys/buf.h>
76 #include <sys/proc.h>
77 #include <sys/user.h>
78
79 #include <uvm/uvm_extern.h>
80
81 #include <machine/bus.h>
82 #include <machine/intr.h>
83
84 #include <dev/scsipi/scsi_all.h>
85 #include <dev/scsipi/scsipi_all.h>
86 #include <dev/scsipi/scsiconf.h>
87
88 #include <dev/ic/ahareg.h>
89 #include <dev/ic/ahavar.h>
90
91 #ifndef DDB
92 #define Debugger() panic("should call debugger here (aha1542.c)")
93 #endif /* ! DDB */
94
95 #define AHA_MAXXFER ((AHA_NSEG - 1) << PGSHIFT)
96
97 #ifdef AHADEBUG
98 int aha_debug = 1;
99 #endif /* AHADEBUG */
100
101 int aha_cmd __P((bus_space_tag_t, bus_space_handle_t, struct aha_softc *, int,
102 u_char *, int, u_char *));
103 integrate void aha_finish_ccbs __P((struct aha_softc *));
104 integrate void aha_reset_ccb __P((struct aha_softc *, struct aha_ccb *));
105 void aha_free_ccb __P((struct aha_softc *, struct aha_ccb *));
106 integrate int aha_init_ccb __P((struct aha_softc *, struct aha_ccb *));
107 struct aha_ccb *aha_get_ccb __P((struct aha_softc *));
108 struct aha_ccb *aha_ccb_phys_kv __P((struct aha_softc *, u_long));
109 void aha_queue_ccb __P((struct aha_softc *, struct aha_ccb *));
110 void aha_collect_mbo __P((struct aha_softc *));
111 void aha_start_ccbs __P((struct aha_softc *));
112 void aha_done __P((struct aha_softc *, struct aha_ccb *));
113 int aha_init __P((struct aha_softc *));
114 void aha_inquire_setup_information __P((struct aha_softc *));
115 void ahaminphys __P((struct buf *));
116 void aha_scsipi_request __P((struct scsipi_channel *,
117 scsipi_adapter_req_t, void *));
118 int aha_poll __P((struct aha_softc *, struct scsipi_xfer *, int));
119 void aha_timeout __P((void *arg));
120 int aha_create_ccbs __P((struct aha_softc *, struct aha_ccb *, int));
121
122 #define AHA_RESET_TIMEOUT 2000 /* time to wait for reset (mSec) */
123 #define AHA_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
124
125 /*
126 * aha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf)
127 *
128 * Activate Adapter command
129 * icnt: number of args (outbound bytes including opcode)
130 * ibuf: argument buffer
131 * ocnt: number of expected returned bytes
132 * obuf: result buffer
133 * wait: number of seconds to wait for response
134 *
135 * Performs an adapter command through the ports. Not to be confused with a
136 * scsi command, which is read in via the DMA; one of the adapter commands
137 * tells it to read in a scsi command.
138 */
139 int
140 aha_cmd(iot, ioh, sc, icnt, ibuf, ocnt, obuf)
141 bus_space_tag_t iot;
142 bus_space_handle_t ioh;
143 struct aha_softc *sc;
144 int icnt, ocnt;
145 u_char *ibuf, *obuf;
146 {
147 const char *name;
148 int i;
149 int wait;
150 u_char sts;
151 u_char opcode = ibuf[0];
152
153 if (sc != NULL)
154 name = sc->sc_dev.dv_xname;
155 else
156 name = "(aha probe)";
157
158 /*
159 * Calculate a reasonable timeout for the command.
160 */
161 switch (opcode) {
162 case AHA_INQUIRE_DEVICES:
163 wait = 90 * 20000;
164 break;
165 default:
166 wait = 1 * 20000;
167 break;
168 }
169
170 /*
171 * Wait for the adapter to go idle, unless it's one of
172 * the commands which don't need this
173 */
174 if (opcode != AHA_MBO_INTR_EN) {
175 for (i = 20000; i; i--) { /* 1 sec? */
176 sts = bus_space_read_1(iot, ioh, AHA_STAT_PORT);
177 if (sts & AHA_STAT_IDLE)
178 break;
179 delay(50);
180 }
181 if (!i) {
182 printf("%s: aha_cmd, host not idle(0x%x)\n",
183 name, sts);
184 return (1);
185 }
186 }
187 /*
188 * Now that it is idle, if we expect output, preflush the
189 * queue feeding to us.
190 */
191 if (ocnt) {
192 while ((bus_space_read_1(iot, ioh, AHA_STAT_PORT)) & AHA_STAT_DF)
193 bus_space_read_1(iot, ioh, AHA_DATA_PORT);
194 }
195 /*
196 * Output the command and the number of arguments given
197 * for each byte, first check the port is empty.
198 */
199 while (icnt--) {
200 for (i = wait; i; i--) {
201 sts = bus_space_read_1(iot, ioh, AHA_STAT_PORT);
202 if (!(sts & AHA_STAT_CDF))
203 break;
204 delay(50);
205 }
206 if (!i) {
207 if (opcode != AHA_INQUIRE_REVISION)
208 printf("%s: aha_cmd, cmd/data port full\n", name);
209 bus_space_write_1(iot, ioh, AHA_CTRL_PORT, AHA_CTRL_SRST);
210 return (1);
211 }
212 bus_space_write_1(iot, ioh, AHA_CMD_PORT, *ibuf++);
213 }
214 /*
215 * If we expect input, loop that many times, each time,
216 * looking for the data register to have valid data
217 */
218 while (ocnt--) {
219 for (i = wait; i; i--) {
220 sts = bus_space_read_1(iot, ioh, AHA_STAT_PORT);
221 if (sts & AHA_STAT_DF)
222 break;
223 delay(50);
224 }
225 if (!i) {
226 if (opcode != AHA_INQUIRE_REVISION)
227 printf("%s: aha_cmd, cmd/data port empty %d\n",
228 name, ocnt);
229 bus_space_write_1(iot, ioh, AHA_CTRL_PORT, AHA_CTRL_SRST);
230 return (1);
231 }
232 *obuf++ = bus_space_read_1(iot, ioh, AHA_DATA_PORT);
233 }
234 /*
235 * Wait for the board to report a finished instruction.
236 * We may get an extra interrupt for the HACC signal, but this is
237 * unimportant.
238 */
239 if (opcode != AHA_MBO_INTR_EN) {
240 for (i = 20000; i; i--) { /* 1 sec? */
241 sts = bus_space_read_1(iot, ioh, AHA_INTR_PORT);
242 /* XXX Need to save this in the interrupt handler? */
243 if (sts & AHA_INTR_HACC)
244 break;
245 delay(50);
246 }
247 if (!i) {
248 printf("%s: aha_cmd, host not finished(0x%x)\n",
249 name, sts);
250 return (1);
251 }
252 }
253 bus_space_write_1(iot, ioh, AHA_CTRL_PORT, AHA_CTRL_IRST);
254 return (0);
255 }
256
257 void
258 aha_attach(sc, apd)
259 struct aha_softc *sc;
260 struct aha_probe_data *apd;
261 {
262 struct scsipi_adapter *adapt = &sc->sc_adapter;
263 struct scsipi_channel *chan = &sc->sc_channel;
264
265 TAILQ_INIT(&sc->sc_free_ccb);
266 TAILQ_INIT(&sc->sc_waiting_ccb);
267
268 /*
269 * Fill in the scsipi_adapter.
270 */
271 memset(adapt, 0, sizeof(*adapt));
272 adapt->adapt_dev = &sc->sc_dev;
273 adapt->adapt_nchannels = 1;
274 /* adapt_openings initialized below */
275 /* adapt_max_periph initialized below */
276 adapt->adapt_request = aha_scsipi_request;
277 adapt->adapt_minphys = ahaminphys;
278
279 /*
280 * Fill in the scsipi_channel.
281 */
282 memset(chan, 0, sizeof(*chan));
283 chan->chan_adapter = adapt;
284 chan->chan_bustype = &scsi_bustype;
285 chan->chan_channel = 0;
286 chan->chan_ntargets = 8;
287 chan->chan_nluns = 8;
288 chan->chan_id = apd->sc_scsi_dev;
289
290 aha_inquire_setup_information(sc);
291 if (aha_init(sc) != 0) {
292 /* Error during initialization! */
293 return;
294 }
295
296 /*
297 * ask the adapter what subunits are present
298 */
299 config_found(&sc->sc_dev, &sc->sc_channel, scsiprint);
300 }
301
302 integrate void
303 aha_finish_ccbs(sc)
304 struct aha_softc *sc;
305 {
306 struct aha_mbx_in *wmbi;
307 struct aha_ccb *ccb;
308 int i;
309
310 wmbi = wmbx->tmbi;
311
312 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
313 AHA_MBI_OFF(wmbi), sizeof(struct aha_mbx_in),
314 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
315
316 if (wmbi->stat == AHA_MBI_FREE) {
317 for (i = 0; i < AHA_MBX_SIZE; i++) {
318 if (wmbi->stat != AHA_MBI_FREE) {
319 printf("%s: mbi not in round-robin order\n",
320 sc->sc_dev.dv_xname);
321 goto AGAIN;
322 }
323 aha_nextmbx(wmbi, wmbx, mbi);
324 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
325 AHA_MBI_OFF(wmbi), sizeof(struct aha_mbx_in),
326 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
327 }
328 #ifdef AHADIAGnot
329 printf("%s: mbi interrupt with no full mailboxes\n",
330 sc->sc_dev.dv_xname);
331 #endif
332 return;
333 }
334
335 AGAIN:
336 do {
337 ccb = aha_ccb_phys_kv(sc, phystol(wmbi->ccb_addr));
338 if (!ccb) {
339 printf("%s: bad mbi ccb pointer; skipping\n",
340 sc->sc_dev.dv_xname);
341 goto next;
342 }
343
344 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
345 AHA_CCB_OFF(ccb), sizeof(struct aha_ccb),
346 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
347
348 #ifdef AHADEBUG
349 if (aha_debug) {
350 u_char *cp = &ccb->scsi_cmd;
351 printf("op=%x %x %x %x %x %x\n",
352 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
353 printf("stat %x for mbi addr = 0x%08x, ",
354 wmbi->stat, wmbi);
355 printf("ccb addr = 0x%x\n", ccb);
356 }
357 #endif /* AHADEBUG */
358
359 switch (wmbi->stat) {
360 case AHA_MBI_OK:
361 case AHA_MBI_ERROR:
362 if ((ccb->flags & CCB_ABORT) != 0) {
363 /*
364 * If we already started an abort, wait for it
365 * to complete before clearing the CCB. We
366 * could instead just clear CCB_SENDING, but
367 * what if the mailbox was already received?
368 * The worst that happens here is that we clear
369 * the CCB a bit later than we need to. BFD.
370 */
371 goto next;
372 }
373 break;
374
375 case AHA_MBI_ABORT:
376 case AHA_MBI_UNKNOWN:
377 /*
378 * Even if the CCB wasn't found, we clear it anyway.
379 * See preceding comment.
380 */
381 break;
382
383 default:
384 printf("%s: bad mbi status %02x; skipping\n",
385 sc->sc_dev.dv_xname, wmbi->stat);
386 goto next;
387 }
388
389 callout_stop(&ccb->xs->xs_callout);
390 aha_done(sc, ccb);
391
392 next:
393 wmbi->stat = AHA_MBI_FREE;
394 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
395 AHA_MBI_OFF(wmbi), sizeof(struct aha_mbx_in),
396 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
397 aha_nextmbx(wmbi, wmbx, mbi);
398 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
399 AHA_MBI_OFF(wmbi), sizeof(struct aha_mbx_in),
400 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
401 } while (wmbi->stat != AHA_MBI_FREE);
402
403 wmbx->tmbi = wmbi;
404 }
405
406 /*
407 * Catch an interrupt from the adaptor
408 */
409 int
410 aha_intr(arg)
411 void *arg;
412 {
413 struct aha_softc *sc = arg;
414 bus_space_tag_t iot = sc->sc_iot;
415 bus_space_handle_t ioh = sc->sc_ioh;
416 u_char sts;
417
418 #ifdef AHADEBUG
419 printf("%s: aha_intr ", sc->sc_dev.dv_xname);
420 #endif /*AHADEBUG */
421
422 /*
423 * First acknowledge the interrupt, Then if it's not telling about
424 * a completed operation just return.
425 */
426 sts = bus_space_read_1(iot, ioh, AHA_INTR_PORT);
427 if ((sts & AHA_INTR_ANYINTR) == 0)
428 return (0);
429 bus_space_write_1(iot, ioh, AHA_CTRL_PORT, AHA_CTRL_IRST);
430
431 #ifdef AHADIAG
432 /* Make sure we clear CCB_SENDING before finishing a CCB. */
433 aha_collect_mbo(sc);
434 #endif
435
436 /* Mail box out empty? */
437 if (sts & AHA_INTR_MBOA) {
438 struct aha_toggle toggle;
439
440 toggle.cmd.opcode = AHA_MBO_INTR_EN;
441 toggle.cmd.enable = 0;
442 aha_cmd(iot, ioh, sc,
443 sizeof(toggle.cmd), (u_char *)&toggle.cmd,
444 0, (u_char *)0);
445 aha_start_ccbs(sc);
446 }
447
448 /* Mail box in full? */
449 if (sts & AHA_INTR_MBIF)
450 aha_finish_ccbs(sc);
451
452 return (1);
453 }
454
455 integrate void
456 aha_reset_ccb(sc, ccb)
457 struct aha_softc *sc;
458 struct aha_ccb *ccb;
459 {
460
461 ccb->flags = 0;
462 }
463
464 /*
465 * A ccb is put onto the free list.
466 */
467 void
468 aha_free_ccb(sc, ccb)
469 struct aha_softc *sc;
470 struct aha_ccb *ccb;
471 {
472 int s;
473
474 s = splbio();
475 aha_reset_ccb(sc, ccb);
476 TAILQ_INSERT_HEAD(&sc->sc_free_ccb, ccb, chain);
477 splx(s);
478 }
479
480 integrate int
481 aha_init_ccb(sc, ccb)
482 struct aha_softc *sc;
483 struct aha_ccb *ccb;
484 {
485 bus_dma_tag_t dmat = sc->sc_dmat;
486 int hashnum, error;
487
488 /*
489 * Create the DMA map for this CCB.
490 */
491 error = bus_dmamap_create(dmat, AHA_MAXXFER, AHA_NSEG, AHA_MAXXFER,
492 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &ccb->dmamap_xfer);
493 if (error) {
494 printf("%s: unable to create ccb DMA map, error = %d\n",
495 sc->sc_dev.dv_xname, error);
496 return (error);
497 }
498
499 /*
500 * put in the phystokv hash table
501 * Never gets taken out.
502 */
503 ccb->hashkey = sc->sc_dmamap_control->dm_segs[0].ds_addr +
504 AHA_CCB_OFF(ccb);
505 hashnum = CCB_HASH(ccb->hashkey);
506 ccb->nexthash = sc->sc_ccbhash[hashnum];
507 sc->sc_ccbhash[hashnum] = ccb;
508 aha_reset_ccb(sc, ccb);
509 return (0);
510 }
511
512 /*
513 * Create a set of ccbs and add them to the free list. Called once
514 * by aha_init(). We return the number of CCBs successfully created.
515 */
516 int
517 aha_create_ccbs(sc, ccbstore, count)
518 struct aha_softc *sc;
519 struct aha_ccb *ccbstore;
520 int count;
521 {
522 struct aha_ccb *ccb;
523 int i, error;
524
525 memset(ccbstore, 0, sizeof(struct aha_ccb) * count);
526 for (i = 0; i < count; i++) {
527 ccb = &ccbstore[i];
528 if ((error = aha_init_ccb(sc, ccb)) != 0) {
529 printf("%s: unable to initialize ccb, error = %d\n",
530 sc->sc_dev.dv_xname, error);
531 goto out;
532 }
533 TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, chain);
534 }
535 out:
536 return (i);
537 }
538
539 /*
540 * Get a free ccb
541 *
542 * If there are none, see if we can allocate a new one. If so, put it in
543 * the hash table too otherwise either return an error or sleep.
544 */
545 struct aha_ccb *
546 aha_get_ccb(sc)
547 struct aha_softc *sc;
548 {
549 struct aha_ccb *ccb;
550 int s;
551
552 s = splbio();
553 ccb = TAILQ_FIRST(&sc->sc_free_ccb);
554 if (ccb != NULL) {
555 TAILQ_REMOVE(&sc->sc_free_ccb, ccb, chain);
556 ccb->flags |= CCB_ALLOC;
557 }
558 splx(s);
559 return (ccb);
560 }
561
562 /*
563 * Given a physical address, find the ccb that it corresponds to.
564 */
565 struct aha_ccb *
566 aha_ccb_phys_kv(sc, ccb_phys)
567 struct aha_softc *sc;
568 u_long ccb_phys;
569 {
570 int hashnum = CCB_HASH(ccb_phys);
571 struct aha_ccb *ccb = sc->sc_ccbhash[hashnum];
572
573 while (ccb) {
574 if (ccb->hashkey == ccb_phys)
575 break;
576 ccb = ccb->nexthash;
577 }
578 return (ccb);
579 }
580
581 /*
582 * Queue a CCB to be sent to the controller, and send it if possible.
583 */
584 void
585 aha_queue_ccb(sc, ccb)
586 struct aha_softc *sc;
587 struct aha_ccb *ccb;
588 {
589
590 TAILQ_INSERT_TAIL(&sc->sc_waiting_ccb, ccb, chain);
591 aha_start_ccbs(sc);
592 }
593
594 /*
595 * Garbage collect mailboxes that are no longer in use.
596 */
597 void
598 aha_collect_mbo(sc)
599 struct aha_softc *sc;
600 {
601 struct aha_mbx_out *wmbo; /* Mail Box Out pointer */
602 #ifdef AHADIAG
603 struct aha_ccb *ccb;
604 #endif
605
606 wmbo = wmbx->cmbo;
607
608 while (sc->sc_mbofull > 0) {
609 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
610 AHA_MBO_OFF(wmbo), sizeof(struct aha_mbx_out),
611 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
612 if (wmbo->cmd != AHA_MBO_FREE)
613 break;
614
615 #ifdef AHADIAG
616 ccb = aha_ccb_phys_kv(sc, phystol(wmbo->ccb_addr));
617 ccb->flags &= ~CCB_SENDING;
618 #endif
619
620 --sc->sc_mbofull;
621 aha_nextmbx(wmbo, wmbx, mbo);
622 }
623
624 wmbx->cmbo = wmbo;
625 }
626
627 /*
628 * Send as many CCBs as we have empty mailboxes for.
629 */
630 void
631 aha_start_ccbs(sc)
632 struct aha_softc *sc;
633 {
634 bus_space_tag_t iot = sc->sc_iot;
635 bus_space_handle_t ioh = sc->sc_ioh;
636 struct aha_mbx_out *wmbo; /* Mail Box Out pointer */
637 struct aha_ccb *ccb;
638
639 wmbo = wmbx->tmbo;
640
641 while ((ccb = sc->sc_waiting_ccb.tqh_first) != NULL) {
642 if (sc->sc_mbofull >= AHA_MBX_SIZE) {
643 aha_collect_mbo(sc);
644 if (sc->sc_mbofull >= AHA_MBX_SIZE) {
645 struct aha_toggle toggle;
646
647 toggle.cmd.opcode = AHA_MBO_INTR_EN;
648 toggle.cmd.enable = 1;
649 aha_cmd(iot, ioh, sc,
650 sizeof(toggle.cmd), (u_char *)&toggle.cmd,
651 0, (u_char *)0);
652 break;
653 }
654 }
655
656 TAILQ_REMOVE(&sc->sc_waiting_ccb, ccb, chain);
657 #ifdef AHADIAG
658 ccb->flags |= CCB_SENDING;
659 #endif
660
661 /* Link ccb to mbo. */
662 ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
663 AHA_CCB_OFF(ccb), wmbo->ccb_addr);
664 if (ccb->flags & CCB_ABORT)
665 wmbo->cmd = AHA_MBO_ABORT;
666 else
667 wmbo->cmd = AHA_MBO_START;
668
669 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
670 AHA_MBO_OFF(wmbo), sizeof(struct aha_mbx_out),
671 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
672
673 /* Tell the card to poll immediately. */
674 bus_space_write_1(iot, ioh, AHA_CMD_PORT, AHA_START_SCSI);
675
676 if ((ccb->xs->xs_control & XS_CTL_POLL) == 0)
677 callout_reset(&ccb->xs->xs_callout,
678 mstohz(ccb->timeout), aha_timeout, ccb);
679
680 ++sc->sc_mbofull;
681 aha_nextmbx(wmbo, wmbx, mbo);
682 }
683
684 wmbx->tmbo = wmbo;
685 }
686
687 /*
688 * We have a ccb which has been processed by the
689 * adaptor, now we look to see how the operation
690 * went. Wake up the owner if waiting
691 */
692 void
693 aha_done(sc, ccb)
694 struct aha_softc *sc;
695 struct aha_ccb *ccb;
696 {
697 bus_dma_tag_t dmat = sc->sc_dmat;
698 struct scsipi_sense_data *s1, *s2;
699 struct scsipi_xfer *xs = ccb->xs;
700
701 SC_DEBUG(xs->xs_periph, SCSIPI_DB2, ("aha_done\n"));
702
703 /*
704 * If we were a data transfer, unload the map that described
705 * the data buffer.
706 */
707 if (xs->datalen) {
708 bus_dmamap_sync(dmat, ccb->dmamap_xfer, 0,
709 ccb->dmamap_xfer->dm_mapsize,
710 (xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMASYNC_POSTREAD :
711 BUS_DMASYNC_POSTWRITE);
712 bus_dmamap_unload(dmat, ccb->dmamap_xfer);
713 }
714
715 /*
716 * Otherwise, put the results of the operation
717 * into the xfer and call whoever started it
718 */
719 #ifdef AHADIAG
720 if (ccb->flags & CCB_SENDING) {
721 printf("%s: exiting ccb still in transit!\n", sc->sc_dev.dv_xname);
722 Debugger();
723 return;
724 }
725 #endif
726 if ((ccb->flags & CCB_ALLOC) == 0) {
727 printf("%s: exiting ccb not allocated!\n", sc->sc_dev.dv_xname);
728 Debugger();
729 return;
730 }
731 if (xs->error == XS_NOERROR) {
732 if (ccb->host_stat != AHA_OK) {
733 switch (ccb->host_stat) {
734 case AHA_SEL_TIMEOUT: /* No response */
735 xs->error = XS_SELTIMEOUT;
736 break;
737 default: /* Other scsi protocol messes */
738 printf("%s: host_stat %x\n",
739 sc->sc_dev.dv_xname, ccb->host_stat);
740 xs->error = XS_DRIVER_STUFFUP;
741 break;
742 }
743 } else if (ccb->target_stat != SCSI_OK) {
744 switch (ccb->target_stat) {
745 case SCSI_CHECK:
746 s1 = (struct scsipi_sense_data *) (((char *) (&ccb->scsi_cmd)) +
747 ccb->scsi_cmd_length);
748 s2 = &xs->sense.scsi_sense;
749 *s2 = *s1;
750 xs->error = XS_SENSE;
751 break;
752 case SCSI_BUSY:
753 xs->error = XS_BUSY;
754 break;
755 default:
756 printf("%s: target_stat %x\n",
757 sc->sc_dev.dv_xname, ccb->target_stat);
758 xs->error = XS_DRIVER_STUFFUP;
759 break;
760 }
761 } else
762 xs->resid = 0;
763 }
764 aha_free_ccb(sc, ccb);
765 scsipi_done(xs);
766 }
767
768 /*
769 * Find the board and find its irq/drq
770 */
771 int
772 aha_find(iot, ioh, sc)
773 bus_space_tag_t iot;
774 bus_space_handle_t ioh;
775 struct aha_probe_data *sc;
776 {
777 int i;
778 u_char sts;
779 struct aha_config config;
780 int irq, drq;
781
782 /*
783 * reset board, If it doesn't respond, assume
784 * that it's not there.. good for the probe
785 */
786
787 bus_space_write_1(iot, ioh, AHA_CTRL_PORT, AHA_CTRL_HRST | AHA_CTRL_SRST);
788
789 delay(100);
790 for (i = AHA_RESET_TIMEOUT; i; i--) {
791 sts = bus_space_read_1(iot, ioh, AHA_STAT_PORT);
792 if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT))
793 break;
794 delay(1000); /* calibrated in msec */
795 }
796 if (!i) {
797 #ifdef AHADEBUG
798 if (aha_debug)
799 printf("aha_find: No answer from adaptec board\n");
800 #endif /* AHADEBUG */
801 return (0);
802 }
803
804 /*
805 * setup DMA channel from jumpers and save int
806 * level
807 */
808 delay(1000); /* for Bustek 545 */
809 config.cmd.opcode = AHA_INQUIRE_CONFIG;
810 aha_cmd(iot, ioh, (struct aha_softc *)0,
811 sizeof(config.cmd), (u_char *)&config.cmd,
812 sizeof(config.reply), (u_char *)&config.reply);
813 switch (config.reply.chan) {
814 case EISADMA:
815 drq = -1;
816 break;
817 case CHAN0:
818 drq = 0;
819 break;
820 case CHAN5:
821 drq = 5;
822 break;
823 case CHAN6:
824 drq = 6;
825 break;
826 case CHAN7:
827 drq = 7;
828 break;
829 default:
830 printf("aha_find: illegal drq setting %x\n", config.reply.chan);
831 return (0);
832 }
833
834 switch (config.reply.intr) {
835 case INT9:
836 irq = 9;
837 break;
838 case INT10:
839 irq = 10;
840 break;
841 case INT11:
842 irq = 11;
843 break;
844 case INT12:
845 irq = 12;
846 break;
847 case INT14:
848 irq = 14;
849 break;
850 case INT15:
851 irq = 15;
852 break;
853 default:
854 printf("aha_find: illegal irq setting %x\n", config.reply.intr);
855 return (0);
856 }
857
858 if (sc) {
859 sc->sc_irq = irq;
860 sc->sc_drq = drq;
861 sc->sc_scsi_dev = config.reply.scsi_dev;
862 }
863
864 return (1);
865 }
866
867 /*
868 * Start the board, ready for normal operation
869 */
870 int
871 aha_init(sc)
872 struct aha_softc *sc;
873 {
874 bus_space_tag_t iot = sc->sc_iot;
875 bus_space_handle_t ioh = sc->sc_ioh;
876 bus_dma_segment_t seg;
877 struct aha_devices devices;
878 struct aha_setup setup;
879 struct aha_mailbox mailbox;
880 int error, i, j, initial_ccbs, rseg;
881
882 /*
883 * XXX
884 * If we are a 1542C or later, disable the extended BIOS so that the
885 * mailbox interface is unlocked.
886 * No need to check the extended BIOS flags as some of the
887 * extensions that cause us problems are not flagged in that byte.
888 */
889 if (!strncmp(sc->sc_model, "1542C", 5)) {
890 struct aha_extbios extbios;
891 struct aha_unlock unlock;
892
893 printf("%s: unlocking mailbox interface\n", sc->sc_dev.dv_xname);
894 extbios.cmd.opcode = AHA_EXT_BIOS;
895 aha_cmd(iot, ioh, sc,
896 sizeof(extbios.cmd), (u_char *)&extbios.cmd,
897 sizeof(extbios.reply), (u_char *)&extbios.reply);
898
899 #ifdef AHADEBUG
900 printf("%s: flags=%02x, mailboxlock=%02x\n",
901 sc->sc_dev.dv_xname,
902 extbios.reply.flags, extbios.reply.mailboxlock);
903 #endif /* AHADEBUG */
904
905 unlock.cmd.opcode = AHA_MBX_ENABLE;
906 unlock.cmd.junk = 0;
907 unlock.cmd.magic = extbios.reply.mailboxlock;
908 aha_cmd(iot, ioh, sc,
909 sizeof(unlock.cmd), (u_char *)&unlock.cmd,
910 0, (u_char *)0);
911 }
912
913 #if 0
914 /*
915 * Change the bus on/off times to not clash with other DMA users.
916 */
917 aha_cmd(iot, ioh, 1, 0, 0, 0, AHA_BUS_ON_TIME_SET, 7);
918 aha_cmd(iot, ioh, 1, 0, 0, 0, AHA_BUS_OFF_TIME_SET, 4);
919 #endif
920
921 /* Inquire Installed Devices (to force synchronous negotiation). */
922 devices.cmd.opcode = AHA_INQUIRE_DEVICES;
923 aha_cmd(iot, ioh, sc,
924 sizeof(devices.cmd), (u_char *)&devices.cmd,
925 sizeof(devices.reply), (u_char *)&devices.reply);
926
927 /* Count installed units */
928 initial_ccbs = 0;
929 for (i = 0; i < 8; i++) {
930 for (j = 0; j < 8; j++) {
931 if (((devices.reply.lun_map[i] >> j) & 1) == 1)
932 initial_ccbs += 1;
933 }
934 }
935 initial_ccbs *= 2;
936 if (initial_ccbs > AHA_CCB_MAX)
937 initial_ccbs = AHA_CCB_MAX;
938 if (initial_ccbs == 0) /* yes, this can happen */
939 initial_ccbs = 2;
940
941 /* Obtain setup information from. */
942 setup.cmd.opcode = AHA_INQUIRE_SETUP;
943 setup.cmd.len = sizeof(setup.reply);
944 aha_cmd(iot, ioh, sc,
945 sizeof(setup.cmd), (u_char *)&setup.cmd,
946 sizeof(setup.reply), (u_char *)&setup.reply);
947
948 printf("%s: %s, %s\n",
949 sc->sc_dev.dv_xname,
950 setup.reply.sync_neg ? "sync" : "async",
951 setup.reply.parity ? "parity" : "no parity");
952
953 for (i = 0; i < 8; i++) {
954 if (!setup.reply.sync[i].valid ||
955 (!setup.reply.sync[i].offset && !setup.reply.sync[i].period))
956 continue;
957 printf("%s targ %d: sync, offset %d, period %dnsec\n",
958 sc->sc_dev.dv_xname, i,
959 setup.reply.sync[i].offset, setup.reply.sync[i].period * 50 + 200);
960 }
961
962 /*
963 * Allocate the mailbox and control blocks.
964 */
965 if ((error = bus_dmamem_alloc(sc->sc_dmat, sizeof(struct aha_control),
966 PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
967 printf("%s: unable to allocate control structures, "
968 "error = %d\n", sc->sc_dev.dv_xname, error);
969 return (error);
970 }
971 if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
972 sizeof(struct aha_control), (caddr_t *)&sc->sc_control,
973 BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
974 printf("%s: unable to map control structures, error = %d\n",
975 sc->sc_dev.dv_xname, error);
976 return (error);
977 }
978
979 /*
980 * Create and load the DMA map used for the mailbox and
981 * control blocks.
982 */
983 if ((error = bus_dmamap_create(sc->sc_dmat, sizeof(struct aha_control),
984 1, sizeof(struct aha_control), 0, BUS_DMA_NOWAIT,
985 &sc->sc_dmamap_control)) != 0) {
986 printf("%s: unable to create control DMA map, error = %d\n",
987 sc->sc_dev.dv_xname, error);
988 return (error);
989 }
990 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_control,
991 sc->sc_control, sizeof(struct aha_control), NULL,
992 BUS_DMA_NOWAIT)) != 0) {
993 printf("%s: unable to load control DMA map, error = %d\n",
994 sc->sc_dev.dv_xname, error);
995 return (error);
996 }
997
998 /*
999 * Initialize the control blocks.
1000 */
1001 i = aha_create_ccbs(sc, sc->sc_control->ac_ccbs, initial_ccbs);
1002 if (i == 0) {
1003 printf("%s: unable to create control blocks\n",
1004 sc->sc_dev.dv_xname);
1005 return (ENOMEM);
1006 } else if (i != initial_ccbs) {
1007 printf("%s: WARNING: only %d of %d control blocks created\n",
1008 sc->sc_dev.dv_xname, i, initial_ccbs);
1009 }
1010
1011 sc->sc_adapter.adapt_openings = i;
1012 sc->sc_adapter.adapt_max_periph = sc->sc_adapter.adapt_openings;
1013
1014 /*
1015 * Set up initial mail box for round-robin operation.
1016 */
1017 for (i = 0; i < AHA_MBX_SIZE; i++) {
1018 wmbx->mbo[i].cmd = AHA_MBO_FREE;
1019 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
1020 AHA_MBO_OFF(&wmbx->mbo[i]), sizeof(struct aha_mbx_out),
1021 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1022 wmbx->mbi[i].stat = AHA_MBI_FREE;
1023 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
1024 AHA_MBI_OFF(&wmbx->mbi[i]), sizeof(struct aha_mbx_in),
1025 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1026 }
1027 wmbx->cmbo = wmbx->tmbo = &wmbx->mbo[0];
1028 wmbx->tmbi = &wmbx->mbi[0];
1029 sc->sc_mbofull = 0;
1030
1031 /* Initialize mail box. */
1032 mailbox.cmd.opcode = AHA_MBX_INIT;
1033 mailbox.cmd.nmbx = AHA_MBX_SIZE;
1034 ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
1035 offsetof(struct aha_control, ac_mbx), mailbox.cmd.addr);
1036 aha_cmd(iot, ioh, sc,
1037 sizeof(mailbox.cmd), (u_char *)&mailbox.cmd,
1038 0, (u_char *)0);
1039 return (0);
1040 }
1041
1042 void
1043 aha_inquire_setup_information(sc)
1044 struct aha_softc *sc;
1045 {
1046 bus_space_tag_t iot = sc->sc_iot;
1047 bus_space_handle_t ioh = sc->sc_ioh;
1048 struct aha_revision revision;
1049 u_char sts;
1050 int i;
1051 char *p;
1052
1053 strcpy(sc->sc_model, "unknown");
1054
1055 /*
1056 * Assume we have a board at this stage, do an adapter inquire
1057 * to find out what type of controller it is. If the command
1058 * fails, we assume it's either a crusty board or an old 1542
1059 * clone, and skip the board-specific stuff.
1060 */
1061 revision.cmd.opcode = AHA_INQUIRE_REVISION;
1062 if (aha_cmd(iot, ioh, sc,
1063 sizeof(revision.cmd), (u_char *)&revision.cmd,
1064 sizeof(revision.reply), (u_char *)&revision.reply)) {
1065 /*
1066 * aha_cmd() already started the reset. It's not clear we
1067 * even need to bother here.
1068 */
1069 for (i = AHA_RESET_TIMEOUT; i; i--) {
1070 sts = bus_space_read_1(iot, ioh, AHA_STAT_PORT);
1071 if (sts == (AHA_STAT_IDLE | AHA_STAT_INIT))
1072 break;
1073 delay(1000);
1074 }
1075 if (!i) {
1076 #ifdef AHADEBUG
1077 printf("aha_init: soft reset failed\n");
1078 #endif /* AHADEBUG */
1079 return;
1080 }
1081 #ifdef AHADEBUG
1082 printf("aha_init: inquire command failed\n");
1083 #endif /* AHADEBUG */
1084 goto noinquire;
1085 }
1086
1087 #ifdef AHADEBUG
1088 printf("%s: inquire %x, %x, %x, %x\n",
1089 sc->sc_dev.dv_xname,
1090 revision.reply.boardid, revision.reply.spec_opts,
1091 revision.reply.revision_1, revision.reply.revision_2);
1092 #endif /* AHADEBUG */
1093
1094 switch (revision.reply.boardid) {
1095 case BOARD_1540_16HEAD_BIOS:
1096 case BOARD_1540_64HEAD_BIOS:
1097 case BOARD_1540:
1098 strcpy(sc->sc_model, "1540");
1099 break;
1100 case BOARD_1542:
1101 strcpy(sc->sc_model, "1540A/1542A/1542B");
1102 break;
1103 case BOARD_1640:
1104 strcpy(sc->sc_model, "1640");
1105 break;
1106 case BOARD_1740:
1107 strcpy(sc->sc_model, "1740");
1108 break;
1109 case BOARD_1542C:
1110 strcpy(sc->sc_model, "1542C");
1111 break;
1112 case BOARD_1542CF:
1113 strcpy(sc->sc_model, "1542CF");
1114 break;
1115 case BOARD_1542CP:
1116 strcpy(sc->sc_model, "1542CP");
1117 break;
1118 }
1119
1120 p = sc->sc_firmware;
1121 *p++ = revision.reply.revision_1;
1122 *p++ = '.';
1123 *p++ = revision.reply.revision_2;
1124 *p = '\0';
1125
1126 noinquire:
1127 printf("%s: model AHA-%s, firmware %s\n",
1128 sc->sc_dev.dv_xname,
1129 sc->sc_model, sc->sc_firmware);
1130 }
1131
1132 void
1133 ahaminphys(bp)
1134 struct buf *bp;
1135 {
1136
1137 if (bp->b_bcount > AHA_MAXXFER)
1138 bp->b_bcount = AHA_MAXXFER;
1139 minphys(bp);
1140 }
1141
1142 /*
1143 * start a scsi operation given the command and the data address. Also needs
1144 * the unit, target and lu.
1145 */
1146
1147 void
1148 aha_scsipi_request(chan, req, arg)
1149 struct scsipi_channel *chan;
1150 scsipi_adapter_req_t req;
1151 void *arg;
1152 {
1153 struct scsipi_xfer *xs;
1154 struct scsipi_periph *periph;
1155 struct aha_softc *sc = (void *)chan->chan_adapter->adapt_dev;
1156 bus_dma_tag_t dmat = sc->sc_dmat;
1157 struct aha_ccb *ccb;
1158 int error, seg, flags, s;
1159
1160
1161 switch (req) {
1162 case ADAPTER_REQ_RUN_XFER:
1163 xs = arg;
1164 periph = xs->xs_periph;
1165 flags = xs->xs_control;
1166
1167 SC_DEBUG(periph, SCSIPI_DB2, ("aha_scsipi_request\n"));
1168
1169 /* Get a CCB to use. */
1170 ccb = aha_get_ccb(sc);
1171 #ifdef DIAGNOSTIC
1172 /*
1173 * This should never happen as we track the resources
1174 * in the mid-layer.
1175 */
1176 if (ccb == NULL) {
1177 scsipi_printaddr(periph);
1178 printf("unable to allocate ccb\n");
1179 panic("aha_scsipi_request");
1180 }
1181 #endif
1182
1183 ccb->xs = xs;
1184 ccb->timeout = xs->timeout;
1185
1186 /*
1187 * Put all the arguments for the xfer in the ccb
1188 */
1189 if (flags & XS_CTL_RESET) {
1190 ccb->opcode = AHA_RESET_CCB;
1191 ccb->scsi_cmd_length = 0;
1192 } else {
1193 /* can't use S/G if zero length */
1194 ccb->opcode = (xs->datalen ? AHA_INIT_SCAT_GATH_CCB
1195 : AHA_INITIATOR_CCB);
1196 memcpy(&ccb->scsi_cmd, xs->cmd,
1197 ccb->scsi_cmd_length = xs->cmdlen);
1198 }
1199
1200 if (xs->datalen) {
1201 /*
1202 * Map the DMA transfer.
1203 */
1204 #ifdef TFS
1205 if (flags & XS_CTL_DATA_UIO) {
1206 error = bus_dmamap_load_uio(dmat,
1207 ccb->dmamap_xfer, (struct uio *)xs->data,
1208 ((flags & XS_CTL_NOSLEEP) ? BUS_DMA_NOWAIT :
1209 BUS_DMA_WAITOK) | BUS_DMA_STREAMING |
1210 ((flags & XS_CTL_DATA_IN) ? BUS_DMA_READ :
1211 BUS_DMA_WRITE));
1212 } else
1213 #endif
1214 {
1215 error = bus_dmamap_load(dmat,
1216 ccb->dmamap_xfer, xs->data, xs->datalen,
1217 NULL,
1218 ((flags & XS_CTL_NOSLEEP) ? BUS_DMA_NOWAIT :
1219 BUS_DMA_WAITOK) | BUS_DMA_STREAMING |
1220 ((flags & XS_CTL_DATA_IN) ? BUS_DMA_READ :
1221 BUS_DMA_WRITE));
1222 }
1223
1224 switch (error) {
1225 case 0:
1226 break;
1227
1228 case ENOMEM:
1229 case EAGAIN:
1230 xs->error = XS_RESOURCE_SHORTAGE;
1231 goto out_bad;
1232
1233 default:
1234 xs->error = XS_DRIVER_STUFFUP;
1235 if (error == EFBIG) {
1236 printf("%s: aha_scsi_cmd, more than %d"
1237 " DMA segments\n",
1238 sc->sc_dev.dv_xname, AHA_NSEG);
1239 } else {
1240 printf("%s: error %d loading DMA map\n",
1241 sc->sc_dev.dv_xname, error);
1242 }
1243 out_bad:
1244 aha_free_ccb(sc, ccb);
1245 scsipi_done(xs);
1246 return;
1247 }
1248
1249 bus_dmamap_sync(dmat, ccb->dmamap_xfer, 0,
1250 ccb->dmamap_xfer->dm_mapsize,
1251 (flags & XS_CTL_DATA_IN) ? BUS_DMASYNC_PREREAD :
1252 BUS_DMASYNC_PREWRITE);
1253
1254 /*
1255 * Load the hardware scatter/gather map with the
1256 * contents of the DMA map.
1257 */
1258 for (seg = 0; seg < ccb->dmamap_xfer->dm_nsegs; seg++) {
1259 ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_addr,
1260 ccb->scat_gath[seg].seg_addr);
1261 ltophys(ccb->dmamap_xfer->dm_segs[seg].ds_len,
1262 ccb->scat_gath[seg].seg_len);
1263 }
1264
1265 ltophys(sc->sc_dmamap_control->dm_segs[0].ds_addr +
1266 AHA_CCB_OFF(ccb) +
1267 offsetof(struct aha_ccb, scat_gath),
1268 ccb->data_addr);
1269 ltophys(ccb->dmamap_xfer->dm_nsegs *
1270 sizeof(struct aha_scat_gath), ccb->data_length);
1271 } else {
1272 /*
1273 * No data xfer, use non S/G values.
1274 */
1275 ltophys(0, ccb->data_addr);
1276 ltophys(0, ccb->data_length);
1277 }
1278
1279 ccb->data_out = 0;
1280 ccb->data_in = 0;
1281 ccb->target = periph->periph_target;
1282 ccb->lun = periph->periph_lun;
1283 ccb->req_sense_length = sizeof(ccb->scsi_sense);
1284 ccb->host_stat = 0x00;
1285 ccb->target_stat = 0x00;
1286 ccb->link_id = 0;
1287 ltophys(0, ccb->link_addr);
1288
1289 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_control,
1290 AHA_CCB_OFF(ccb), sizeof(struct aha_ccb),
1291 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1292
1293 s = splbio();
1294 aha_queue_ccb(sc, ccb);
1295 splx(s);
1296
1297 SC_DEBUG(periph, SCSIPI_DB3, ("cmd_sent\n"));
1298 if ((flags & XS_CTL_POLL) == 0)
1299 return;
1300
1301 /* Not allowed to use interrupts, poll for completion. */
1302 if (aha_poll(sc, xs, ccb->timeout)) {
1303 aha_timeout(ccb);
1304 if (aha_poll(sc, xs, ccb->timeout))
1305 aha_timeout(ccb);
1306 }
1307 return;
1308
1309 case ADAPTER_REQ_GROW_RESOURCES:
1310 /* XXX Not supported. */
1311 return;
1312
1313 case ADAPTER_REQ_SET_XFER_MODE:
1314 /*
1315 * Can't really do this on the Adaptec; it has
1316 * its own config mechanism, but we do know how
1317 * to query what the firmware negotiated.
1318 */
1319 /* XXX XXX XXX */
1320 return;
1321 }
1322 }
1323
1324 /*
1325 * Poll a particular unit, looking for a particular xs
1326 */
1327 int
1328 aha_poll(sc, xs, count)
1329 struct aha_softc *sc;
1330 struct scsipi_xfer *xs;
1331 int count;
1332 {
1333 bus_space_tag_t iot = sc->sc_iot;
1334 bus_space_handle_t ioh = sc->sc_ioh;
1335
1336 /* timeouts are in msec, so we loop in 1000 usec cycles */
1337 while (count) {
1338 /*
1339 * If we had interrupts enabled, would we
1340 * have got an interrupt?
1341 */
1342 if (bus_space_read_1(iot, ioh, AHA_INTR_PORT) & AHA_INTR_ANYINTR)
1343 aha_intr(sc);
1344 if (xs->xs_status & XS_STS_DONE)
1345 return (0);
1346 delay(1000); /* only happens in boot so ok */
1347 count--;
1348 }
1349 return (1);
1350 }
1351
1352 void
1353 aha_timeout(arg)
1354 void *arg;
1355 {
1356 struct aha_ccb *ccb = arg;
1357 struct scsipi_xfer *xs = ccb->xs;
1358 struct scsipi_periph *periph = xs->xs_periph;
1359 struct aha_softc *sc =
1360 (void *)periph->periph_channel->chan_adapter->adapt_dev;
1361 int s;
1362
1363 scsipi_printaddr(periph);
1364 printf("timed out");
1365
1366 s = splbio();
1367
1368 #ifdef AHADIAG
1369 /*
1370 * If The ccb's mbx is not free, then the board has gone south?
1371 */
1372 aha_collect_mbo(sc);
1373 if (ccb->flags & CCB_SENDING) {
1374 printf("%s: not taking commands!\n", sc->sc_dev.dv_xname);
1375 Debugger();
1376 }
1377 #endif
1378
1379 /*
1380 * If it has been through before, then
1381 * a previous abort has failed, don't
1382 * try abort again
1383 */
1384 if (ccb->flags & CCB_ABORT) {
1385 /* abort timed out */
1386 printf(" AGAIN\n");
1387 /* XXX Must reset! */
1388 } else {
1389 /* abort the operation that has timed out */
1390 printf("\n");
1391 ccb->xs->error = XS_TIMEOUT;
1392 ccb->timeout = AHA_ABORT_TIMEOUT;
1393 ccb->flags |= CCB_ABORT;
1394 aha_queue_ccb(sc, ccb);
1395 }
1396
1397 splx(s);
1398 }
Cache object: fda1dafb0c3de179da94e61e20ab758e
|