FreeBSD/Linux Kernel Cross Reference
sys/dev/eisa/ahb.c
1 /* $NetBSD: ahb.c,v 1.47 2006/11/16 01:32:50 christos 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: ahb.c,v 1.47 2006/11/16 01:32:50 christos Exp $");
57
58 #include "opt_ddb.h"
59
60 #undef AHBDEBUG
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/kernel.h>
65 #include <sys/errno.h>
66 #include <sys/ioctl.h>
67 #include <sys/device.h>
68 #include <sys/malloc.h>
69 #include <sys/buf.h>
70 #include <sys/proc.h>
71 #include <sys/user.h>
72
73 #include <uvm/uvm_extern.h>
74
75 #include <machine/bus.h>
76 #include <machine/intr.h>
77
78 #include <dev/scsipi/scsi_all.h>
79 #include <dev/scsipi/scsipi_all.h>
80 #include <dev/scsipi/scsiconf.h>
81
82 #include <dev/eisa/eisareg.h>
83 #include <dev/eisa/eisavar.h>
84 #include <dev/eisa/eisadevs.h>
85 #include <dev/eisa/ahbreg.h>
86
87 #ifndef DDB
88 #define Debugger() panic("should call debugger here (aha1742.c)")
89 #endif /* ! DDB */
90
91 #define AHB_ECB_MAX 32 /* store up to 32 ECBs at one time */
92 #define ECB_HASH_SIZE 32 /* hash table size for phystokv */
93 #define ECB_HASH_SHIFT 9
94 #define ECB_HASH(x) ((((long)(x))>>ECB_HASH_SHIFT) & (ECB_HASH_SIZE - 1))
95
96 #define AHB_MAXXFER ((AHB_NSEG - 1) << PGSHIFT)
97
98 struct ahb_softc {
99 struct device sc_dev;
100
101 bus_space_tag_t sc_iot;
102 bus_space_handle_t sc_ioh;
103 bus_dma_tag_t sc_dmat;
104 void *sc_ih;
105
106 bus_dmamap_t sc_dmamap_ecb; /* maps the ecbs */
107 struct ahb_ecb *sc_ecbs; /* all our ecbs */
108
109 struct ahb_ecb *sc_ecbhash[ECB_HASH_SIZE];
110 TAILQ_HEAD(, ahb_ecb) sc_free_ecb;
111 struct ahb_ecb *sc_immed_ecb; /* an outstanding immediete command */
112 int sc_numecbs;
113
114 struct scsipi_adapter sc_adapter;
115 struct scsipi_channel sc_channel;
116 };
117
118 /*
119 * Offset of an ECB from the beginning of the ECB DMA mapping.
120 */
121 #define AHB_ECB_OFF(e) (((u_long)(e)) - ((u_long)&sc->sc_ecbs[0]))
122
123 struct ahb_probe_data {
124 int sc_irq;
125 int sc_scsi_dev;
126 };
127
128 static void ahb_send_mbox(struct ahb_softc *, int, struct ahb_ecb *);
129 static void ahb_send_immed(struct ahb_softc *, u_int32_t, struct ahb_ecb *);
130 static int ahbintr(void *);
131 static void ahb_free_ecb(struct ahb_softc *, struct ahb_ecb *);
132 static struct ahb_ecb *ahb_get_ecb(struct ahb_softc *);
133 static struct ahb_ecb *ahb_ecb_phys_kv(struct ahb_softc *, physaddr);
134 static void ahb_done(struct ahb_softc *, struct ahb_ecb *);
135 static int ahb_find(bus_space_tag_t, bus_space_handle_t,
136 struct ahb_probe_data *);
137 static int ahb_init(struct ahb_softc *);
138 static void ahbminphys(struct buf *);
139 static void ahb_scsipi_request(struct scsipi_channel *,
140 scsipi_adapter_req_t, void *);
141 static int ahb_poll(struct ahb_softc *, struct scsipi_xfer *, int);
142 static void ahb_timeout(void *);
143 static int ahb_create_ecbs(struct ahb_softc *, struct ahb_ecb *, int);
144
145 static int ahb_init_ecb(struct ahb_softc *, struct ahb_ecb *);
146
147 static int ahbmatch(struct device *, struct cfdata *, void *);
148 static void ahbattach(struct device *, struct device *, void *);
149
150 CFATTACH_DECL(ahb, sizeof(struct ahb_softc),
151 ahbmatch, ahbattach, NULL, NULL);
152
153 #define AHB_ABORT_TIMEOUT 2000 /* time to wait for abort (mSec) */
154
155 /*
156 * Check the slots looking for a board we recognise
157 * If we find one, note it's address (slot) and call
158 * the actual probe routine to check it out.
159 */
160 static int
161 ahbmatch(struct device *parent, struct cfdata *match,
162 void *aux)
163 {
164 struct eisa_attach_args *ea = aux;
165 bus_space_tag_t iot = ea->ea_iot;
166 bus_space_handle_t ioh;
167 int rv;
168
169 /* must match one of our known ID strings */
170 if (strcmp(ea->ea_idstring, "ADP0000") &&
171 strcmp(ea->ea_idstring, "ADP0001") &&
172 strcmp(ea->ea_idstring, "ADP0002") &&
173 strcmp(ea->ea_idstring, "ADP0400"))
174 return (0);
175
176 if (bus_space_map(iot,
177 EISA_SLOT_ADDR(ea->ea_slot) + AHB_EISA_SLOT_OFFSET, AHB_EISA_IOSIZE,
178 0, &ioh))
179 return (0);
180
181 rv = !ahb_find(iot, ioh, NULL);
182
183 bus_space_unmap(iot, ioh, AHB_EISA_IOSIZE);
184
185 return (rv);
186 }
187
188 /*
189 * Attach all the sub-devices we can find
190 */
191 static void
192 ahbattach(struct device *parent, struct device *self, void *aux)
193 {
194 struct eisa_attach_args *ea = aux;
195 struct ahb_softc *sc = device_private(self);
196 bus_space_tag_t iot = ea->ea_iot;
197 bus_space_handle_t ioh;
198 eisa_chipset_tag_t ec = ea->ea_ec;
199 eisa_intr_handle_t ih;
200 const char *model, *intrstr;
201 struct ahb_probe_data apd;
202 struct scsipi_adapter *adapt = &sc->sc_adapter;
203 struct scsipi_channel *chan = &sc->sc_channel;
204
205 if (!strcmp(ea->ea_idstring, "ADP0000"))
206 model = EISA_PRODUCT_ADP0000;
207 else if (!strcmp(ea->ea_idstring, "ADP0001"))
208 model = EISA_PRODUCT_ADP0001;
209 else if (!strcmp(ea->ea_idstring, "ADP0002"))
210 model = EISA_PRODUCT_ADP0002;
211 else if (!strcmp(ea->ea_idstring, "ADP0400"))
212 model = EISA_PRODUCT_ADP0400;
213 else
214 model = "unknown model!";
215 printf(": %s\n", model);
216
217 if (bus_space_map(iot,
218 EISA_SLOT_ADDR(ea->ea_slot) + AHB_EISA_SLOT_OFFSET, AHB_EISA_IOSIZE,
219 0, &ioh))
220 panic("ahbattach: could not map I/O addresses");
221
222 sc->sc_iot = iot;
223 sc->sc_ioh = ioh;
224 sc->sc_dmat = ea->ea_dmat;
225 if (ahb_find(iot, ioh, &apd))
226 panic("ahbattach: ahb_find failed!");
227
228 TAILQ_INIT(&sc->sc_free_ecb);
229
230 /*
231 * Fill in the scsipi_adapter.
232 */
233 memset(adapt, 0, sizeof(*adapt));
234 adapt->adapt_dev = &sc->sc_dev;
235 adapt->adapt_nchannels = 1;
236 /* adapt_openings initialized below */
237 adapt->adapt_max_periph = 4; /* XXX arbitrary? */
238 adapt->adapt_request = ahb_scsipi_request;
239 adapt->adapt_minphys = ahbminphys;
240
241 /*
242 * Fill in the scsipi_channel.
243 */
244 memset(chan, 0, sizeof(*chan));
245 chan->chan_adapter = adapt;
246 chan->chan_bustype = &scsi_bustype;
247 chan->chan_channel = 0;
248 chan->chan_ntargets = 8;
249 chan->chan_nluns = 8;
250 chan->chan_id = apd.sc_scsi_dev;
251
252 if (ahb_init(sc) != 0) {
253 /* Error during initialization! */
254 return;
255 }
256
257 if (eisa_intr_map(ec, apd.sc_irq, &ih)) {
258 printf("%s: couldn't map interrupt (%d)\n",
259 sc->sc_dev.dv_xname, apd.sc_irq);
260 return;
261 }
262 intrstr = eisa_intr_string(ec, ih);
263 sc->sc_ih = eisa_intr_establish(ec, ih, IST_LEVEL, IPL_BIO,
264 ahbintr, sc);
265 if (sc->sc_ih == NULL) {
266 printf("%s: couldn't establish interrupt",
267 sc->sc_dev.dv_xname);
268 if (intrstr != NULL)
269 printf(" at %s", intrstr);
270 printf("\n");
271 return;
272 }
273 if (intrstr != NULL)
274 printf("%s: interrupting at %s\n", sc->sc_dev.dv_xname,
275 intrstr);
276
277 /*
278 * ask the adapter what subunits are present
279 */
280 config_found(self, &sc->sc_channel, scsiprint);
281 }
282
283 /*
284 * Function to send a command out through a mailbox
285 */
286 static void
287 ahb_send_mbox(struct ahb_softc *sc, int opcode, struct ahb_ecb *ecb)
288 {
289 bus_space_tag_t iot = sc->sc_iot;
290 bus_space_handle_t ioh = sc->sc_ioh;
291 int wait = 300; /* 1ms should be enough */
292
293 while (--wait) {
294 if ((bus_space_read_1(iot, ioh, G2STAT) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
295 == (G2STAT_MBOX_EMPTY))
296 break;
297 delay(10);
298 }
299 if (!wait) {
300 printf("%s: board not responding\n", sc->sc_dev.dv_xname);
301 Debugger();
302 }
303
304 /*
305 * don't know if this will work.
306 * XXX WHAT DOES THIS COMMENT MEAN?! --thorpej
307 */
308 bus_space_write_4(iot, ioh, MBOXOUT0,
309 sc->sc_dmamap_ecb->dm_segs[0].ds_addr + AHB_ECB_OFF(ecb));
310 bus_space_write_1(iot, ioh, ATTN, opcode |
311 ecb->xs->xs_periph->periph_target);
312
313 if ((ecb->xs->xs_control & XS_CTL_POLL) == 0)
314 callout_reset(&ecb->xs->xs_callout,
315 mstohz(ecb->timeout), ahb_timeout, ecb);
316 }
317
318 /*
319 * Function to send an immediate type command to the adapter
320 */
321 static void
322 ahb_send_immed(struct ahb_softc *sc, u_int32_t cmd, struct ahb_ecb *ecb)
323 {
324 bus_space_tag_t iot = sc->sc_iot;
325 bus_space_handle_t ioh = sc->sc_ioh;
326 int wait = 100; /* 1 ms enough? */
327
328 while (--wait) {
329 if ((bus_space_read_1(iot, ioh, G2STAT) & (G2STAT_BUSY | G2STAT_MBOX_EMPTY))
330 == (G2STAT_MBOX_EMPTY))
331 break;
332 delay(10);
333 }
334 if (!wait) {
335 printf("%s: board not responding\n", sc->sc_dev.dv_xname);
336 Debugger();
337 }
338
339 bus_space_write_4(iot, ioh, MBOXOUT0, cmd); /* don't know this will work */
340 bus_space_write_1(iot, ioh, G2CNTRL, G2CNTRL_SET_HOST_READY);
341 bus_space_write_1(iot, ioh, ATTN, OP_IMMED |
342 ecb->xs->xs_periph->periph_target);
343
344 if ((ecb->xs->xs_control & XS_CTL_POLL) == 0)
345 callout_reset(&ecb->xs->xs_callout,
346 mstohz(ecb->timeout), ahb_timeout, ecb);
347 }
348
349 /*
350 * Catch an interrupt from the adaptor
351 */
352 static int
353 ahbintr(void *arg)
354 {
355 struct ahb_softc *sc = arg;
356 bus_space_tag_t iot = sc->sc_iot;
357 bus_space_handle_t ioh = sc->sc_ioh;
358 struct ahb_ecb *ecb;
359 u_char ahbstat;
360 u_int32_t mboxval;
361
362 #ifdef AHBDEBUG
363 printf("%s: ahbintr ", sc->sc_dev.dv_xname);
364 #endif /* AHBDEBUG */
365
366 if ((bus_space_read_1(iot, ioh, G2STAT) & G2STAT_INT_PEND) == 0)
367 return 0;
368
369 for (;;) {
370 /*
371 * First get all the information and then
372 * acknowledge the interrupt
373 */
374 ahbstat = bus_space_read_1(iot, ioh, G2INTST);
375 mboxval = bus_space_read_4(iot, ioh, MBOXIN0);
376 bus_space_write_1(iot, ioh, G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
377
378 #ifdef AHBDEBUG
379 printf("status = 0x%x ", ahbstat);
380 #endif /* AHBDEBUG */
381
382 /*
383 * Process the completed operation
384 */
385 switch (ahbstat & G2INTST_INT_STAT) {
386 case AHB_ECB_OK:
387 case AHB_ECB_RECOVERED:
388 case AHB_ECB_ERR:
389 ecb = ahb_ecb_phys_kv(sc, mboxval);
390 if (!ecb) {
391 printf("%s: BAD ECB RETURNED!\n",
392 sc->sc_dev.dv_xname);
393 goto next; /* whatever it was, it'll timeout */
394 }
395 break;
396
397 case AHB_IMMED_ERR:
398 ecb = sc->sc_immed_ecb;
399 sc->sc_immed_ecb = 0;
400 ecb->flags |= ECB_IMMED_FAIL;
401 break;
402
403 case AHB_IMMED_OK:
404 ecb = sc->sc_immed_ecb;
405 sc->sc_immed_ecb = 0;
406 break;
407
408 default:
409 printf("%s: unexpected interrupt %x\n",
410 sc->sc_dev.dv_xname, ahbstat);
411 goto next;
412 }
413
414 callout_stop(&ecb->xs->xs_callout);
415 ahb_done(sc, ecb);
416
417 next:
418 if ((bus_space_read_1(iot, ioh, G2STAT) & G2STAT_INT_PEND) == 0)
419 return 1;
420 }
421 }
422
423 static inline void
424 ahb_reset_ecb(struct ahb_softc *sc, struct ahb_ecb *ecb)
425 {
426
427 ecb->flags = 0;
428 }
429
430 /*
431 * A ecb (and hence a mbx-out is put onto the
432 * free list.
433 */
434 static void
435 ahb_free_ecb(struct ahb_softc *sc, struct ahb_ecb *ecb)
436 {
437 int s;
438
439 s = splbio();
440 ahb_reset_ecb(sc, ecb);
441 TAILQ_INSERT_HEAD(&sc->sc_free_ecb, ecb, chain);
442 splx(s);
443 }
444
445 /*
446 * Create a set of ecbs and add them to the free list.
447 */
448 static int
449 ahb_init_ecb(struct ahb_softc *sc, struct ahb_ecb *ecb)
450 {
451 bus_dma_tag_t dmat = sc->sc_dmat;
452 int hashnum, error;
453
454 /*
455 * Create the DMA map for this ECB.
456 */
457 error = bus_dmamap_create(dmat, AHB_MAXXFER, AHB_NSEG, AHB_MAXXFER,
458 0, BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &ecb->dmamap_xfer);
459 if (error) {
460 printf("%s: can't create ecb dmamap_xfer\n",
461 sc->sc_dev.dv_xname);
462 return (error);
463 }
464
465 /*
466 * put in the phystokv hash table
467 * Never gets taken out.
468 */
469 ecb->hashkey = sc->sc_dmamap_ecb->dm_segs[0].ds_addr +
470 AHB_ECB_OFF(ecb);
471 hashnum = ECB_HASH(ecb->hashkey);
472 ecb->nexthash = sc->sc_ecbhash[hashnum];
473 sc->sc_ecbhash[hashnum] = ecb;
474 ahb_reset_ecb(sc, ecb);
475 return (0);
476 }
477
478 static int
479 ahb_create_ecbs(struct ahb_softc *sc, struct ahb_ecb *ecbstore, int count)
480 {
481 struct ahb_ecb *ecb;
482 int i, error;
483
484 bzero(ecbstore, sizeof(struct ahb_ecb) * count);
485 for (i = 0; i < count; i++) {
486 ecb = &ecbstore[i];
487 if ((error = ahb_init_ecb(sc, ecb)) != 0) {
488 printf("%s: unable to initialize ecb, error = %d\n",
489 sc->sc_dev.dv_xname, error);
490 goto out;
491 }
492 TAILQ_INSERT_TAIL(&sc->sc_free_ecb, ecb, chain);
493 }
494 out:
495 return (i);
496 }
497
498 /*
499 * Get a free ecb
500 *
501 * If there are none, see if we can allocate a new one. If so, put it in the
502 * hash table too otherwise either return an error or sleep.
503 */
504 static struct ahb_ecb *
505 ahb_get_ecb(struct ahb_softc *sc)
506 {
507 struct ahb_ecb *ecb;
508 int s;
509
510 s = splbio();
511 ecb = TAILQ_FIRST(&sc->sc_free_ecb);
512 if (ecb != NULL) {
513 TAILQ_REMOVE(&sc->sc_free_ecb, ecb, chain);
514 ecb->flags |= ECB_ALLOC;
515 }
516 splx(s);
517 return (ecb);
518 }
519
520 /*
521 * given a physical address, find the ecb that it corresponds to.
522 */
523 static struct ahb_ecb *
524 ahb_ecb_phys_kv(struct ahb_softc *sc, physaddr ecb_phys)
525 {
526 int hashnum = ECB_HASH(ecb_phys);
527 struct ahb_ecb *ecb = sc->sc_ecbhash[hashnum];
528
529 while (ecb) {
530 if (ecb->hashkey == ecb_phys)
531 break;
532 ecb = ecb->nexthash;
533 }
534 return ecb;
535 }
536
537 /*
538 * We have a ecb which has been processed by the adaptor, now we look to see
539 * how the operation went.
540 */
541 static void
542 ahb_done(struct ahb_softc *sc, struct ahb_ecb *ecb)
543 {
544 bus_dma_tag_t dmat = sc->sc_dmat;
545 struct scsi_sense_data *s1, *s2;
546 struct scsipi_xfer *xs = ecb->xs;
547
548 SC_DEBUG(xs->xs_periph, SCSIPI_DB2, ("ahb_done\n"));
549
550 bus_dmamap_sync(dmat, sc->sc_dmamap_ecb,
551 AHB_ECB_OFF(ecb), sizeof(struct ahb_ecb),
552 BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
553
554 /*
555 * If we were a data transfer, unload the map that described
556 * the data buffer.
557 */
558 if (xs->datalen) {
559 bus_dmamap_sync(dmat, ecb->dmamap_xfer, 0,
560 ecb->dmamap_xfer->dm_mapsize,
561 (xs->xs_control & XS_CTL_DATA_IN) ? BUS_DMASYNC_POSTREAD :
562 BUS_DMASYNC_POSTWRITE);
563 bus_dmamap_unload(dmat, ecb->dmamap_xfer);
564 }
565
566 /*
567 * Otherwise, put the results of the operation
568 * into the xfer and call whoever started it
569 */
570 if ((ecb->flags & ECB_ALLOC) == 0) {
571 printf("%s: exiting ecb not allocated!\n", sc->sc_dev.dv_xname);
572 Debugger();
573 }
574 if (ecb->flags & ECB_IMMED) {
575 if (ecb->flags & ECB_IMMED_FAIL)
576 xs->error = XS_DRIVER_STUFFUP;
577 goto done;
578 }
579 if (xs->error == XS_NOERROR) {
580 if (ecb->ecb_status.host_stat != HS_OK) {
581 switch (ecb->ecb_status.host_stat) {
582 case HS_TIMED_OUT: /* No response */
583 xs->error = XS_SELTIMEOUT;
584 break;
585 default: /* Other scsi protocol messes */
586 printf("%s: host_stat %x\n",
587 sc->sc_dev.dv_xname, ecb->ecb_status.host_stat);
588 xs->error = XS_DRIVER_STUFFUP;
589 }
590 } else if (ecb->ecb_status.target_stat != SCSI_OK) {
591 switch (ecb->ecb_status.target_stat) {
592 case SCSI_CHECK:
593 s1 = &ecb->ecb_sense;
594 s2 = &xs->sense.scsi_sense;
595 *s2 = *s1;
596 xs->error = XS_SENSE;
597 break;
598 case SCSI_BUSY:
599 xs->error = XS_BUSY;
600 break;
601 default:
602 printf("%s: target_stat %x\n",
603 sc->sc_dev.dv_xname, ecb->ecb_status.target_stat);
604 xs->error = XS_DRIVER_STUFFUP;
605 }
606 } else
607 xs->resid = 0;
608 }
609 done:
610 ahb_free_ecb(sc, ecb);
611 scsipi_done(xs);
612 }
613
614 /*
615 * Start the board, ready for normal operation
616 */
617 static int
618 ahb_find(bus_space_tag_t iot, bus_space_handle_t ioh, struct ahb_probe_data *sc)
619 {
620 u_char intdef;
621 int i, irq, busid;
622 int wait = 1000; /* 1 sec enough? */
623
624 bus_space_write_1(iot, ioh, PORTADDR, PORTADDR_ENHANCED);
625
626 #define NO_NO 1
627 #ifdef NO_NO
628 /*
629 * reset board, If it doesn't respond, assume
630 * that it's not there.. good for the probe
631 */
632 bus_space_write_1(iot, ioh, G2CNTRL, G2CNTRL_HARD_RESET);
633 delay(1000);
634 bus_space_write_1(iot, ioh, G2CNTRL, 0);
635 delay(10000);
636 while (--wait) {
637 if ((bus_space_read_1(iot, ioh, G2STAT) & G2STAT_BUSY) == 0)
638 break;
639 delay(1000);
640 }
641 if (!wait) {
642 #ifdef AHBDEBUG
643 printf("ahb_find: No answer from aha1742 board\n");
644 #endif /* AHBDEBUG */
645 return ENXIO;
646 }
647 i = bus_space_read_1(iot, ioh, MBOXIN0);
648 if (i) {
649 printf("self test failed, val = 0x%x\n", i);
650 return EIO;
651 }
652
653 /* Set it again, just to be sure. */
654 bus_space_write_1(iot, ioh, PORTADDR, PORTADDR_ENHANCED);
655 #endif
656
657 while (bus_space_read_1(iot, ioh, G2STAT) & G2STAT_INT_PEND) {
658 printf(".");
659 bus_space_write_1(iot, ioh, G2CNTRL, G2CNTRL_CLEAR_EISA_INT);
660 delay(10000);
661 }
662
663 intdef = bus_space_read_1(iot, ioh, INTDEF);
664 switch (intdef & 0x07) {
665 case INT9:
666 irq = 9;
667 break;
668 case INT10:
669 irq = 10;
670 break;
671 case INT11:
672 irq = 11;
673 break;
674 case INT12:
675 irq = 12;
676 break;
677 case INT14:
678 irq = 14;
679 break;
680 case INT15:
681 irq = 15;
682 break;
683 default:
684 printf("illegal int setting %x\n", intdef);
685 return EIO;
686 }
687
688 bus_space_write_1(iot, ioh, INTDEF, (intdef | INTEN)); /* make sure we can interrupt */
689
690 /* who are we on the scsi bus? */
691 busid = (bus_space_read_1(iot, ioh, SCSIDEF) & HSCSIID);
692
693 /* if we want to return data, do so now */
694 if (sc) {
695 sc->sc_irq = irq;
696 sc->sc_scsi_dev = busid;
697 }
698
699 /*
700 * Note that we are going and return (to probe)
701 */
702 return 0;
703 }
704
705 static int
706 ahb_init(struct ahb_softc *sc)
707 {
708 bus_dma_segment_t seg;
709 int i, error, rseg;
710
711 #define ECBSIZE (AHB_ECB_MAX * sizeof(struct ahb_ecb))
712
713 /*
714 * Allocate the ECBs.
715 */
716 if ((error = bus_dmamem_alloc(sc->sc_dmat, ECBSIZE,
717 PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) {
718 printf("%s: unable to allocate ecbs, error = %d\n",
719 sc->sc_dev.dv_xname, error);
720 return (error);
721 }
722 if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg,
723 ECBSIZE, (caddr_t *)&sc->sc_ecbs,
724 BUS_DMA_NOWAIT|BUS_DMA_COHERENT)) != 0) {
725 printf("%s: unable to map ecbs, error = %d\n",
726 sc->sc_dev.dv_xname, error);
727 return (error);
728 }
729
730 /*
731 * Create and load the DMA map used for the ecbs.
732 */
733 if ((error = bus_dmamap_create(sc->sc_dmat, ECBSIZE,
734 1, ECBSIZE, 0, BUS_DMA_NOWAIT, &sc->sc_dmamap_ecb)) != 0) {
735 printf("%s: unable to create ecb DMA map, error = %d\n",
736 sc->sc_dev.dv_xname, error);
737 return (error);
738 }
739 if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap_ecb,
740 sc->sc_ecbs, ECBSIZE, NULL, BUS_DMA_NOWAIT)) != 0) {
741 printf("%s: unable to load ecb DMA map, error = %d\n",
742 sc->sc_dev.dv_xname, error);
743 return (error);
744 }
745
746 #undef ECBSIZE
747
748 /*
749 * Initialize the ecbs.
750 */
751 i = ahb_create_ecbs(sc, sc->sc_ecbs, AHB_ECB_MAX);
752 if (i == 0) {
753 printf("%s: unable to create ecbs\n",
754 sc->sc_dev.dv_xname);
755 return (ENOMEM);
756 } else if (i != AHB_ECB_MAX) {
757 printf("%s: WARNING: only %d of %d ecbs created\n",
758 sc->sc_dev.dv_xname, i, AHB_ECB_MAX);
759 }
760
761 sc->sc_adapter.adapt_openings = i;
762
763 return (0);
764 }
765
766 static void
767 ahbminphys(struct buf *bp)
768 {
769
770 if (bp->b_bcount > AHB_MAXXFER)
771 bp->b_bcount = AHB_MAXXFER;
772 minphys(bp);
773 }
774
775 /*
776 * start a scsi operation given the command and the data address. Also needs
777 * the unit, target and lu.
778 */
779 static void
780 ahb_scsipi_request(struct scsipi_channel *chan, scsipi_adapter_req_t req,
781 void *arg)
782 {
783 struct scsipi_xfer *xs;
784 struct scsipi_periph *periph;
785 struct ahb_softc *sc = (void *)chan->chan_adapter->adapt_dev;
786 bus_dma_tag_t dmat = sc->sc_dmat;
787 struct ahb_ecb *ecb;
788 int error, seg, flags, s;
789
790 switch (req) {
791 case ADAPTER_REQ_RUN_XFER:
792 xs = arg;
793 periph = xs->xs_periph;
794 flags = xs->xs_control;
795
796 SC_DEBUG(periph, SCSIPI_DB2, ("ahb_scsipi_request\n"));
797
798 /* Get an ECB to use. */
799 ecb = ahb_get_ecb(sc);
800 #ifdef DIAGNOSTIC
801 /*
802 * This should never happen as we track the resources
803 * in the mid-layer.
804 */
805 if (ecb == NULL) {
806 scsipi_printaddr(periph);
807 printf("unable to allocate ecb\n");
808 panic("ahb_scsipi_request");
809 }
810 #endif
811
812 ecb->xs = xs;
813 ecb->timeout = xs->timeout;
814
815 /*
816 * If it's a reset, we need to do an 'immediate'
817 * command, and store its ecb for later
818 * if there is already an immediate waiting,
819 * then WE must wait
820 */
821 if (flags & XS_CTL_RESET) {
822 ecb->flags |= ECB_IMMED;
823 if (sc->sc_immed_ecb) {
824 ahb_free_ecb(sc, ecb);
825 xs->error = XS_BUSY;
826 scsipi_done(xs);
827 return;
828 }
829 sc->sc_immed_ecb = ecb;
830
831 s = splbio();
832 ahb_send_immed(sc, AHB_TARG_RESET, ecb);
833 splx(s);
834
835 if ((flags & XS_CTL_POLL) == 0)
836 return;
837
838 /*
839 * If we can't use interrupts, poll on completion
840 */
841 if (ahb_poll(sc, xs, ecb->timeout))
842 ahb_timeout(ecb);
843 return;
844 }
845
846 /*
847 * Put all the arguments for the xfer in the ecb
848 */
849 if (xs->cmdlen > sizeof(ecb->scsi_cmd)) {
850 printf("%s: cmdlen %d too large for ECB\n",
851 sc->sc_dev.dv_xname, xs->cmdlen);
852 xs->error = XS_DRIVER_STUFFUP;
853 goto out_bad;
854 }
855 ecb->opcode = ECB_SCSI_OP;
856 ecb->opt1 = ECB_SES /*| ECB_DSB*/ | ECB_ARS;
857 ecb->opt2 = periph->periph_lun | ECB_NRB;
858 bcopy(xs->cmd, &ecb->scsi_cmd,
859 ecb->scsi_cmd_length = xs->cmdlen);
860 ecb->sense_ptr = sc->sc_dmamap_ecb->dm_segs[0].ds_addr +
861 AHB_ECB_OFF(ecb) + offsetof(struct ahb_ecb, ecb_sense);
862 ecb->req_sense_length = sizeof(ecb->ecb_sense);
863 ecb->status = sc->sc_dmamap_ecb->dm_segs[0].ds_addr +
864 AHB_ECB_OFF(ecb) + offsetof(struct ahb_ecb, ecb_status);
865 ecb->ecb_status.host_stat = 0x00;
866 ecb->ecb_status.target_stat = 0x00;
867
868 if (xs->datalen) {
869 /*
870 * Map the DMA transfer.
871 */
872 #ifdef TFS
873 if (flags & XS_CTL_DATA_UIO) {
874 error = bus_dmamap_load_uio(sc->sc_dmat,
875 ecb->dmamap_xfer, (struct uio *)xs->data,
876 BUS_DMA_NOWAIT);
877 } else
878 #endif /* TFS */
879 {
880 error = bus_dmamap_load(sc->sc_dmat,
881 ecb->dmamap_xfer, xs->data, xs->datalen,
882 NULL, BUS_DMA_NOWAIT);
883 }
884
885 switch (error) {
886 case 0:
887 break;
888
889 case ENOMEM:
890 case EAGAIN:
891 xs->error = XS_RESOURCE_SHORTAGE;
892 goto out_bad;
893
894 default:
895 xs->error = XS_DRIVER_STUFFUP;
896 printf("%s: error %d loading DMA map\n",
897 sc->sc_dev.dv_xname, error);
898 out_bad:
899 ahb_free_ecb(sc, ecb);
900 scsipi_done(xs);
901 return;
902 }
903
904 bus_dmamap_sync(dmat, ecb->dmamap_xfer, 0,
905 ecb->dmamap_xfer->dm_mapsize,
906 (flags & XS_CTL_DATA_IN) ? BUS_DMASYNC_PREREAD :
907 BUS_DMASYNC_PREWRITE);
908
909 /*
910 * Load the hardware scatter/gather map with the
911 * contents of the DMA map.
912 */
913 for (seg = 0; seg < ecb->dmamap_xfer->dm_nsegs; seg++) {
914 ecb->ahb_dma[seg].seg_addr =
915 ecb->dmamap_xfer->dm_segs[seg].ds_addr;
916 ecb->ahb_dma[seg].seg_len =
917 ecb->dmamap_xfer->dm_segs[seg].ds_len;
918 }
919
920 ecb->data_addr = sc->sc_dmamap_ecb->dm_segs[0].ds_addr +
921 AHB_ECB_OFF(ecb) +
922 offsetof(struct ahb_ecb, ahb_dma);
923 ecb->data_length = ecb->dmamap_xfer->dm_nsegs *
924 sizeof(struct ahb_dma_seg);
925 ecb->opt1 |= ECB_S_G;
926 } else { /* No data xfer, use non S/G values */
927 ecb->data_addr = (physaddr)0;
928 ecb->data_length = 0;
929 }
930 ecb->link_addr = (physaddr)0;
931
932 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap_ecb,
933 AHB_ECB_OFF(ecb), sizeof(struct ahb_ecb),
934 BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
935
936 s = splbio();
937 ahb_send_mbox(sc, OP_START_ECB, ecb);
938 splx(s);
939
940 if ((flags & XS_CTL_POLL) == 0)
941 return;
942
943 /*
944 * If we can't use interrupts, poll on completion
945 */
946 if (ahb_poll(sc, xs, ecb->timeout)) {
947 ahb_timeout(ecb);
948 if (ahb_poll(sc, xs, ecb->timeout))
949 ahb_timeout(ecb);
950 }
951 return;
952
953 case ADAPTER_REQ_GROW_RESOURCES:
954 /* XXX Not supported. */
955 return;
956
957 case ADAPTER_REQ_SET_XFER_MODE:
958 /* XXX How do we do this? */
959 return;
960 }
961 }
962
963 /*
964 * Function to poll for command completion when in poll mode
965 */
966 static int
967 ahb_poll(struct ahb_softc *sc, struct scsipi_xfer *xs, int count)
968 { /* in msec */
969 bus_space_tag_t iot = sc->sc_iot;
970 bus_space_handle_t ioh = sc->sc_ioh;
971
972 while (count) {
973 /*
974 * If we had interrupts enabled, would we
975 * have got an interrupt?
976 */
977 if (bus_space_read_1(iot, ioh, G2STAT) & G2STAT_INT_PEND)
978 ahbintr(sc);
979 if (xs->xs_status & XS_STS_DONE)
980 return 0;
981 delay(1000);
982 count--;
983 }
984 return 1;
985 }
986
987 static void
988 ahb_timeout(void *arg)
989 {
990 struct ahb_ecb *ecb = arg;
991 struct scsipi_xfer *xs = ecb->xs;
992 struct scsipi_periph *periph = xs->xs_periph;
993 struct ahb_softc *sc =
994 (void *)periph->periph_channel->chan_adapter->adapt_dev;
995 int s;
996
997 scsipi_printaddr(periph);
998 printf("timed out");
999
1000 s = splbio();
1001
1002 if (ecb->flags & ECB_IMMED) {
1003 printf("\n");
1004 ecb->flags |= ECB_IMMED_FAIL;
1005 /* XXX Must reset! */
1006 } else
1007
1008 /*
1009 * If it has been through before, then
1010 * a previous abort has failed, don't
1011 * try abort again
1012 */
1013 if (ecb->flags & ECB_ABORT) {
1014 /* abort timed out */
1015 printf(" AGAIN\n");
1016 /* XXX Must reset! */
1017 } else {
1018 /* abort the operation that has timed out */
1019 printf("\n");
1020 ecb->xs->error = XS_TIMEOUT;
1021 ecb->timeout = AHB_ABORT_TIMEOUT;
1022 ecb->flags |= ECB_ABORT;
1023 ahb_send_mbox(sc, OP_ABORT_ECB, ecb);
1024 }
1025
1026 splx(s);
1027 }
Cache object: d1834dcbd01460d63cb444968e5b8887
|