FreeBSD/Linux Kernel Cross Reference
sys/dev/wds/wd7000.c
1 /*
2 * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
3 * Copyright (c) 2000 Sergey A. Babkin
4 * All rights reserved.
5 *
6 * Written by Olof Johansson (offe@ludd.luth.se) 1995.
7 * Based on code written by Theo de Raadt (deraadt@fsa.ca).
8 * Resurrected, ported to CAM and generally cleaned up by Sergey Babkin
9 * <babkin@bellatlantic.net> or <babkin@users.sourceforge.net>.
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 at Ludd, University of Lule}
22 * and by the FreeBSD project.
23 * 4. The name of the author may not be used to endorse or promote products
24 * derived from this software without specific prior written permission
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * $FreeBSD: releng/5.1/sys/dev/wds/wd7000.c 113581 2003-04-16 20:57:35Z phk $
38 */
39
40 /* All bugs are subject to removal without further notice */
41
42 /*
43 * offe 01/07/95
44 *
45 * This version of the driver _still_ doesn't implement scatter/gather for the
46 * WD7000-FASST2. This is due to the fact that my controller doesn't seem to
47 * support it. That, and the lack of documentation makes it impossible for me
48 * to implement it. What I've done instead is allocated a local buffer,
49 * contiguous buffer big enough to handle the requests. I haven't seen any
50 * read/write bigger than 64k, so I allocate a buffer of 64+16k. The data
51 * that needs to be DMA'd to/from the controller is copied to/from that
52 * buffer before/after the command is sent to the card.
53 *
54 * SB 03/30/00
55 *
56 * An intermediate buffer is needed anyway to make sure that the buffer is
57 * located under 16MB, otherwise it's out of reach of ISA cards. I've added
58 * optimizations to allocate space in buffer in fragments.
59 */
60
61 /*
62 * Jumpers: (see The Ref(TM) for more info)
63 * W1/W2 - interrupt selection:
64 * W1 (1-2) IRQ3, (3-4) IRQ4, (5-6) IRQ5, (7-8) IRQ7, (9-10) IRQ9
65 * W2 (21-22) IRQ10, (19-20) IRQ11, (17-18) IRQ12, (15-16) IRQ14, (13-14) IRQ15
66 *
67 * W2 - DRQ/DACK selection, DRQ and DACK must be the same:
68 * (5-6) DRQ5 (11-12) DACK5
69 * (3-4) DRQ6 (9-10) DACK6
70 * (1-2) DRQ7 (7-8) DACK7
71 *
72 * W3 - I/O address selection: open pair of pins (OFF) means 1, jumpered (ON) means 0
73 * pair (1-2) is bit 3, ..., pair (9-10) is bit 7. All the other bits are equal
74 * to the value 0x300. In bitwise representation that would be:
75 * 0 0 1 1 (9-10) (7-8) (5-6) (3-4) (1-2) 0 0 0
76 * For example, address 0x3C0, bitwise 1111000000 will be represented as:
77 * (9-10) OFF, (7-8) OFF, (5-6) ON, (3-4) ON, (1-2) ON
78 *
79 * W4 - BIOS address: open pair of pins (OFF) means 1, jumpered (ON) means 0
80 * pair (1-2) is bit 13, ..., pair (7-8) is bit 16. All the other bits are
81 * equal to the value 0xC0000. In bitwise representation that would be:
82 * 1 1 0 (7-8) (5-6) (3-4) (1-2) 0 0000 0000 0000
83 * For example, address 0xD8000 will be represented as:
84 * (7-8) OFF, (5-6) OFF, (3-4) ON, (1-2) ON
85 *
86 * W98 (on newer cards) - BIOS enabled; on older cards just remove the BIOS
87 * chip to disable it
88 * W99 (on newer cards) - ROM size (1-2) OFF, (3-4) ON
89 *
90 * W5 - terminator power
91 * ON - host supplies term. power
92 * OFF - target supplies term. power
93 *
94 * W6, W9 - floppy support (a bit cryptic):
95 * W6 ON, W9 ON - disabled
96 * W6 OFF, W9 ON - enabled with HardCard only
97 * W6 OFF, W9 OFF - enabled with no hardCard or Combo
98 *
99 * Default: I/O 0x350, IRQ15, DMA6
100 */
101
102 /*
103 * debugging levels:
104 * 0 - disabled
105 * 1 - print debugging messages
106 * 2 - collect debugging messages in an internal log buffer which can be
107 * printed later by calling wds_printlog from DDB
108 *
109 * Both kind of logs are heavy and interact significantly with the timing
110 * of commands, so the observed problems may become invisible if debug
111 * logging is enabled.
112 *
113 * The light-weight logging facility may be enabled by defining
114 * WDS_ENABLE_SMALLOG as 1. It has very little overhead and allows observing
115 * the traces of various race conditions without affectiong them but the log is
116 * quite terse. The small log can be printer from DDB by calling
117 * wds_printsmallog.
118 */
119 #ifndef WDS_DEBUG
120 #define WDS_DEBUG 0
121 #endif
122
123 #ifndef WDS_ENABLE_SMALLOG
124 #define WDS_ENABLE_SMALLOG 0
125 #endif
126
127 #include <sys/types.h>
128 #include <sys/param.h>
129 #include <sys/systm.h>
130 #include <sys/errno.h>
131 #include <sys/kernel.h>
132 #include <sys/assym.h>
133
134 #include <sys/bio.h>
135 #include <sys/buf.h>
136
137 #include <cam/cam.h>
138 #include <cam/cam_ccb.h>
139 #include <cam/cam_sim.h>
140 #include <cam/cam_xpt_sim.h>
141 #include <cam/cam_debug.h>
142 #include <cam/scsi/scsi_all.h>
143 #include <cam/scsi/scsi_message.h>
144
145 #include <machine/clock.h>
146
147 #include <vm/vm.h>
148 #include <vm/vm_param.h>
149 #include <vm/pmap.h>
150
151 #include <sys/module.h>
152 #include <sys/bus.h>
153 #include <machine/bus.h>
154 #include <machine/resource.h>
155 #include <sys/rman.h>
156
157 #include <isa/isavar.h>
158 #include <isa/pnpvar.h>
159
160 #define WDSTOPHYS(wp, a) ( ((u_long)a) - ((u_long)wp->dx) + ((u_long)wp->dx_p) )
161 #define WDSTOVIRT(wp, a) ( ((char *)a) - ((char*)wp->dx_p) + ((char *)wp->dx) )
162
163 /* 0x10000 (64k) should be enough. But just to be sure... */
164 #define BUFSIZ 0x12000
165 /* buffer fragment size, no more than 32 frags per buffer */
166 #define FRAGSIZ 0x1000
167
168
169 /* WD7000 registers */
170 #define WDS_STAT 0 /* read */
171 #define WDS_IRQSTAT 1 /* read */
172
173 #define WDS_CMD 0 /* write */
174 #define WDS_IRQACK 1 /* write */
175 #define WDS_HCR 2 /* write */
176
177 #define WDS_NPORTS 4 /* number of ports used */
178
179 /* WDS_STAT (read) defs */
180 #define WDS_IRQ 0x80
181 #define WDS_RDY 0x40
182 #define WDS_REJ 0x20
183 #define WDS_INIT 0x10
184
185 /* WDS_IRQSTAT (read) defs */
186 #define WDSI_MASK 0xc0
187 #define WDSI_ERR 0x00
188 #define WDSI_MFREE 0x80
189 #define WDSI_MSVC 0xc0
190
191 /* WDS_CMD (write) defs */
192 #define WDSC_NOOP 0x00
193 #define WDSC_INIT 0x01
194 #define WDSC_DISUNSOL 0x02 /* disable unsolicited ints */
195 #define WDSC_ENAUNSOL 0x03 /* enable unsolicited ints */
196 #define WDSC_IRQMFREE 0x04 /* interrupt on free RQM */
197 #define WDSC_SCSIRESETSOFT 0x05 /* soft reset */
198 #define WDSC_SCSIRESETHARD 0x06 /* hard reset ack */
199 #define WDSC_MSTART(m) (0x80 + (m)) /* start mailbox */
200 #define WDSC_MMSTART(m) (0xc0 + (m)) /* start all mailboxes */
201
202 /* WDS_HCR (write) defs */
203 #define WDSH_IRQEN 0x08
204 #define WDSH_DRQEN 0x04
205 #define WDSH_SCSIRESET 0x02
206 #define WDSH_ASCRESET 0x01
207
208 struct wds_cmd {
209 u_int8_t cmd;
210 u_int8_t targ;
211 u_int8_t scb[12];
212 u_int8_t stat;
213 u_int8_t venderr;
214 u_int8_t len[3];
215 u_int8_t data[3];
216 u_int8_t next[3];
217 u_int8_t write;
218 u_int8_t xx[6];
219 };
220
221 struct wds_req {
222 struct wds_cmd cmd;
223 union ccb *ccb;
224 enum {
225 WR_DONE = 0x01,
226 WR_SENSE = 0x02
227 } flags;
228 u_int8_t *buf; /* address of linear data buffer */
229 u_int32_t mask; /* mask of allocated fragments */
230 u_int8_t ombn;
231 u_int8_t id; /* number of request */
232 };
233
234 #define WDSX_SCSICMD 0x00
235 #define WDSX_OPEN_RCVBUF 0x80
236 #define WDSX_RCV_CMD 0x81
237 #define WDSX_RCV_DATA 0x82
238 #define WDSX_RCV_DATASTAT 0x83
239 #define WDSX_SND_DATA 0x84
240 #define WDSX_SND_DATASTAT 0x85
241 #define WDSX_SND_CMDSTAT 0x86
242 #define WDSX_READINIT 0x88
243 #define WDSX_READSCSIID 0x89
244 #define WDSX_SETUNSOLIRQMASK 0x8a
245 #define WDSX_GETUNSOLIRQMASK 0x8b
246 #define WDSX_GETFIRMREV 0x8c
247 #define WDSX_EXECDIAG 0x8d
248 #define WDSX_SETEXECPARM 0x8e
249 #define WDSX_GETEXECPARM 0x8f
250
251 struct wds_mb {
252 u_int8_t stat;
253 u_int8_t addr[3];
254 };
255 /* ICMB status value */
256 #define ICMB_OK 0x01
257 #define ICMB_OKERR 0x02
258 #define ICMB_ETIME 0x04
259 #define ICMB_ERESET 0x05
260 #define ICMB_ETARCMD 0x06
261 #define ICMB_ERESEL 0x80
262 #define ICMB_ESEL 0x81
263 #define ICMB_EABORT 0x82
264 #define ICMB_ESRESET 0x83
265 #define ICMB_EHRESET 0x84
266
267 struct wds_setup {
268 u_int8_t cmd;
269 u_int8_t scsi_id;
270 u_int8_t buson_t;
271 u_int8_t busoff_t;
272 u_int8_t xx;
273 u_int8_t mbaddr[3];
274 u_int8_t nomb;
275 u_int8_t nimb;
276 };
277
278 /* the code depends on equality of these parameters */
279 #define MAXSIMUL 8
280 #define WDS_NOMB MAXSIMUL
281 #define WDS_NIMB MAXSIMUL
282
283 static int fragsiz;
284 static int nfrags;
285
286 /* structure for data exchange with controller */
287
288 struct wdsdx {
289 struct wds_req req[MAXSIMUL];
290 struct wds_mb ombs[MAXSIMUL];
291 struct wds_mb imbs[MAXSIMUL];
292 u_int8_t data[BUFSIZ];
293 };
294
295 /* structure softc */
296
297 struct wds {
298 device_t dev;
299 int unit;
300 int addr;
301 int drq;
302 struct cam_sim *sim; /* SIM descriptor for this card */
303 struct cam_path *path; /* wildcard path for this card */
304 char want_wdsr; /* resource shortage flag */
305 u_int32_t data_free;
306 u_int32_t wdsr_free;
307 struct wdsdx *dx;
308 struct wdsdx *dx_p; /* physical address */
309 struct resource *port_r;
310 int port_rid;
311 struct resource *drq_r;
312 int drq_rid;
313 struct resource *intr_r;
314 int intr_rid;
315 void *intr_cookie;
316 bus_dma_tag_t bustag;
317 bus_dmamap_t busmap;
318 };
319
320 #define ccb_wdsr spriv_ptr1 /* for wds request */
321
322 static int wds_probe(device_t dev);
323 static int wds_attach(device_t dev);
324 static void wds_intr(struct wds *wp);
325
326 static void wds_action(struct cam_sim * sim, union ccb * ccb);
327 static void wds_poll(struct cam_sim * sim);
328
329 static int wds_preinit(struct wds *wp);
330 static int wds_init(struct wds *wp);
331
332 static void wds_alloc_callback(void *arg, bus_dma_segment_t *seg,
333 int nseg, int error);
334 static void wds_free_resources(struct wds *wp);
335
336 static struct wds_req *wdsr_alloc(struct wds *wp);
337
338 static void wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio);
339 static void wdsr_ccb_done(struct wds *wp, struct wds_req *r,
340 union ccb *ccb, u_int32_t status);
341
342 static void wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat);
343 static int wds_runsense(struct wds *wp, struct wds_req *r);
344 static int wds_getvers(struct wds *wp);
345
346 static int wds_cmd(int base, u_int8_t * p, int l);
347 static void wds_wait(int reg, int mask, int val);
348
349 static struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys);
350
351 static u_int32_t frag_alloc(struct wds *wp, int size, u_int8_t **res,
352 u_int32_t *maskp);
353 static void frag_free(struct wds *wp, u_int32_t mask);
354
355 void wds_print(void);
356
357 #if WDS_ENABLE_SMALLOG==1
358 static __inline void smallog(char c);
359 void wds_printsmallog(void);
360 #endif /* SMALLOG */
361
362 /* SCSI ID of the adapter itself */
363 #ifndef WDS_HBA_ID
364 #define WDS_HBA_ID 7
365 #endif
366
367 #if WDS_DEBUG == 2
368 #define LOGLINESIZ 81
369 #define NLOGLINES 300
370 #define DBX wds_nextlog(), LOGLINESIZ,
371 #define DBG snprintf
372
373 static char wds_log[NLOGLINES][LOGLINESIZ];
374 static int logwrite = 0, logread = 0;
375 static char *wds_nextlog(void);
376 void wds_printlog(void);
377
378 #elif WDS_DEBUG != 0
379 #define DBX
380 #define DBG printf
381 #else
382 #define DBX
383 #define DBG if(0) printf
384 #endif
385
386 /* the table of supported bus methods */
387 static device_method_t wds_isa_methods[] = {
388 DEVMETHOD(device_probe, wds_probe),
389 DEVMETHOD(device_attach, wds_attach),
390 { 0, 0 }
391 };
392
393 static driver_t wds_isa_driver = {
394 "wds",
395 wds_isa_methods,
396 sizeof(struct wds),
397 };
398
399 static devclass_t wds_devclass;
400
401 DRIVER_MODULE(wds, isa, wds_isa_driver, wds_devclass, 0, 0);
402
403 #if WDS_ENABLE_SMALLOG==1
404 #define SMALLOGSIZ 512
405 static char wds_smallog[SMALLOGSIZ];
406 static char *wds_smallogp = wds_smallog;
407 static char wds_smallogover = 0;
408
409 static __inline void
410 smallog(char c)
411 {
412 *wds_smallogp = c;
413 if (++wds_smallogp == &wds_smallog[SMALLOGSIZ]) {
414 wds_smallogp = wds_smallog;
415 wds_smallogover = 1;
416 }
417 }
418
419 #define smallog2(a, b) (smallog(a), smallog(b))
420 #define smallog3(a, b, c) (smallog(a), smallog(b), smallog(c))
421 #define smallog4(a, b, c, d) (smallog(a),smallog(b),smallog(c),smallog(d))
422
423 void
424 wds_printsmallog(void)
425 {
426 int i;
427 char *p;
428
429 printf("wds: ");
430 p = wds_smallogover ? wds_smallogp : wds_smallog;
431 i = 0;
432 do {
433 printf("%c", *p);
434 if (++p == &wds_smallog[SMALLOGSIZ])
435 p = wds_smallog;
436 if (++i == 70) {
437 i = 0;
438 printf("\nwds: ");
439 }
440 } while (p != wds_smallogp);
441 printf("\n");
442 }
443 #else
444 #define smallog(a)
445 #define smallog2(a, b)
446 #define smallog3(a, b, c)
447 #define smallog4(a, b, c, d)
448 #endif /* SMALLOG */
449
450 static int
451 wds_probe(device_t dev)
452 {
453 struct wds *wp;
454 int error = 0;
455 int irq;
456
457 /* No pnp support */
458 if (isa_get_vendorid(dev))
459 return (ENXIO);
460
461 wp = (struct wds *) device_get_softc(dev);
462 wp->unit = device_get_unit(dev);
463 wp->dev = dev;
464
465 wp->addr = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/);
466 if (wp->addr == 0 || wp->addr <0x300
467 || wp->addr > 0x3f8 || wp->addr & 0x7) {
468 device_printf(dev, "invalid port address 0x%x\n", wp->addr);
469 return (ENXIO);
470 }
471
472 if (bus_set_resource(dev, SYS_RES_IOPORT, 0, wp->addr, WDS_NPORTS) < 0)
473 return (ENXIO);
474
475 /* get the DRQ */
476 wp->drq = bus_get_resource_start(dev, SYS_RES_DRQ, 0 /*rid*/);
477 if (wp->drq < 5 || wp->drq > 7) {
478 device_printf(dev, "invalid DRQ %d\n", wp->drq);
479 return (ENXIO);
480 }
481
482 /* get the IRQ */
483 irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0 /*rid*/);
484 if (irq < 3) {
485 device_printf(dev, "invalid IRQ %d\n", irq);
486 return (ENXIO);
487 }
488
489 wp->port_rid = 0;
490 wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &wp->port_rid,
491 /*start*/ 0, /*end*/ ~0,
492 /*count*/ 0, RF_ACTIVE);
493 if (wp->port_r == NULL)
494 return (ENXIO);
495
496 error = wds_preinit(wp);
497
498 /*
499 * We cannot hold resources between probe and
500 * attach as we may never be attached.
501 */
502 wds_free_resources(wp);
503
504 return (error);
505 }
506
507 static int
508 wds_attach(device_t dev)
509 {
510 struct wds *wp;
511 struct cam_devq *devq;
512 struct cam_sim *sim;
513 struct cam_path *pathp;
514 int i;
515 int error = 0;
516
517 wp = (struct wds *)device_get_softc(dev);
518
519 wp->port_rid = 0;
520 wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT, &wp->port_rid,
521 /*start*/ 0, /*end*/ ~0,
522 /*count*/ 0, RF_ACTIVE);
523 if (wp->port_r == NULL)
524 return (ENXIO);
525
526 /* We must now release resources on error. */
527
528 wp->drq_rid = 0;
529 wp->drq_r = bus_alloc_resource(dev, SYS_RES_DRQ, &wp->drq_rid,
530 /*start*/ 0, /*end*/ ~0,
531 /*count*/ 0, RF_ACTIVE);
532 if (wp->drq_r == NULL)
533 goto bad;
534
535 wp->intr_rid = 0;
536 wp->intr_r = bus_alloc_resource(dev, SYS_RES_IRQ, &wp->intr_rid,
537 /*start*/ 0, /*end*/ ~0,
538 /*count*/ 0, RF_ACTIVE);
539 if (wp->intr_r == NULL)
540 goto bad;
541 error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY,
542 (driver_intr_t *)wds_intr, (void *)wp,
543 &wp->intr_cookie);
544 if (error)
545 goto bad;
546
547 /* now create the memory buffer */
548 error = bus_dma_tag_create(NULL, /*alignment*/4,
549 /*boundary*/0,
550 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
551 /*highaddr*/ BUS_SPACE_MAXADDR,
552 /*filter*/ NULL, /*filterarg*/ NULL,
553 /*maxsize*/ sizeof(* wp->dx),
554 /*nsegments*/ 1,
555 /*maxsegsz*/ sizeof(* wp->dx), /*flags*/ 0,
556 &wp->bustag);
557 if (error)
558 goto bad;
559
560 error = bus_dmamem_alloc(wp->bustag, (void **)&wp->dx,
561 /*flags*/ 0, &wp->busmap);
562 if (error)
563 goto bad;
564
565 bus_dmamap_load(wp->bustag, wp->busmap, (void *)wp->dx,
566 sizeof(* wp->dx), wds_alloc_callback,
567 (void *)&wp->dx_p, /*flags*/0);
568
569 /* initialize the wds_req structures on this unit */
570 for(i=0; i<MAXSIMUL; i++) {
571 wp->dx->req[i].id = i;
572 wp->wdsr_free |= 1<<i;
573 }
574
575 /* initialize the memory buffer allocation for this unit */
576 if (BUFSIZ / FRAGSIZ > 32) {
577 fragsiz = (BUFSIZ / 32) & ~0x01; /* keep it word-aligned */
578 device_printf(dev, "data buffer fragment size too small. "
579 "BUFSIZE / FRAGSIZE must be <= 32\n");
580 } else
581 fragsiz = FRAGSIZ & ~0x01; /* keep it word-aligned */
582
583 wp->data_free = 0;
584 nfrags = 0;
585 for (i = fragsiz; i <= BUFSIZ; i += fragsiz) {
586 nfrags++;
587 wp->data_free = (wp->data_free << 1) | 1;
588 }
589
590 /* complete the hardware initialization */
591 if (wds_init(wp) != 0)
592 goto bad;
593
594 if (wds_getvers(wp) == -1)
595 device_printf(dev, "getvers failed\n");
596 device_printf(dev, "using %d bytes / %d frags for dma buffer\n",
597 BUFSIZ, nfrags);
598
599 devq = cam_simq_alloc(MAXSIMUL);
600 if (devq == NULL)
601 goto bad;
602
603 sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp,
604 wp->unit, 1, 1, devq);
605 if (sim == NULL) {
606 cam_simq_free(devq);
607 goto bad;
608 }
609 wp->sim = sim;
610
611 if (xpt_bus_register(sim, 0) != CAM_SUCCESS) {
612 cam_sim_free(sim, /* free_devq */ TRUE);
613 goto bad;
614 }
615 if (xpt_create_path(&pathp, /* periph */ NULL,
616 cam_sim_path(sim), CAM_TARGET_WILDCARD,
617 CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
618 xpt_bus_deregister(cam_sim_path(sim));
619 cam_sim_free(sim, /* free_devq */ TRUE);
620 goto bad;
621 }
622 wp->path = pathp;
623
624 return (0);
625
626 bad:
627 wds_free_resources(wp);
628 if (error)
629 return (error);
630 else /* exact error is unknown */
631 return (ENXIO);
632 }
633
634 /* callback to save the physical address */
635 static void
636 wds_alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error)
637 {
638 *(bus_addr_t *)arg = seg[0].ds_addr;
639 }
640
641 static void
642 wds_free_resources(struct wds *wp)
643 {
644 /* check every resource and free if not zero */
645
646 /* interrupt handler */
647 if (wp->intr_r) {
648 bus_teardown_intr(wp->dev, wp->intr_r, wp->intr_cookie);
649 bus_release_resource(wp->dev, SYS_RES_IRQ, wp->intr_rid,
650 wp->intr_r);
651 wp->intr_r = 0;
652 }
653
654 /* all kinds of memory maps we could have allocated */
655 if (wp->dx_p) {
656 bus_dmamap_unload(wp->bustag, wp->busmap);
657 wp->dx_p = 0;
658 }
659 if (wp->dx) { /* wp->busmap may be legitimately equal to 0 */
660 /* the map will also be freed */
661 bus_dmamem_free(wp->bustag, wp->dx, wp->busmap);
662 wp->dx = 0;
663 }
664 if (wp->bustag) {
665 bus_dma_tag_destroy(wp->bustag);
666 wp->bustag = 0;
667 }
668 /* release all the bus resources */
669 if (wp->drq_r) {
670 bus_release_resource(wp->dev, SYS_RES_DRQ,
671 wp->drq_rid, wp->drq_r);
672 wp->drq_r = 0;
673 }
674 if (wp->port_r) {
675 bus_release_resource(wp->dev, SYS_RES_IOPORT,
676 wp->port_rid, wp->port_r);
677 wp->port_r = 0;
678 }
679 }
680
681 /* allocate contiguous fragments from the buffer */
682 static u_int32_t
683 frag_alloc(struct wds *wp, int size, u_int8_t **res, u_int32_t *maskp)
684 {
685 int i;
686 u_int32_t mask;
687 u_int32_t free;
688
689 if (size > fragsiz * nfrags)
690 return (CAM_REQ_TOO_BIG);
691
692 mask = 1; /* always allocate at least 1 fragment */
693 for (i = fragsiz; i < size; i += fragsiz)
694 mask = (mask << 1) | 1;
695
696 free = wp->data_free;
697 if(free != 0) {
698 i = ffs(free)-1; /* ffs counts bits from 1 */
699 for (mask <<= i; i < nfrags; i++) {
700 if ((free & mask) == mask) {
701 wp->data_free &= ~mask; /* mark frags as busy */
702 *maskp = mask;
703 *res = &wp->dx->data[fragsiz * i];
704 DBG(DBX "wds%d: allocated buffer mask=0x%x\n",
705 wp->unit, mask);
706 return (CAM_REQ_CMP);
707 }
708 if (mask & 0x80000000)
709 break;
710
711 mask <<= 1;
712 }
713 }
714 return (CAM_REQUEUE_REQ); /* no free memory now, try later */
715 }
716
717 static void
718 frag_free(struct wds *wp, u_int32_t mask)
719 {
720 wp->data_free |= mask; /* mark frags as free */
721 DBG(DBX "wds%d: freed buffer mask=0x%x\n", wp->unit, mask);
722 }
723
724 static struct wds_req *
725 wdsr_alloc(struct wds *wp)
726 {
727 struct wds_req *r;
728 int x;
729 int i;
730
731 r = NULL;
732 x = splcam();
733
734 /* anyway most of the time only 1 or 2 commands will
735 * be active because SCSI disconnect is not supported
736 * by hardware, so the search should be fast enough
737 */
738 i = ffs(wp->wdsr_free) - 1;
739 if(i < 0) {
740 splx(x);
741 return (NULL);
742 }
743 wp->wdsr_free &= ~ (1<<i);
744 r = &wp->dx->req[i];
745 r->flags = 0; /* reset all flags */
746 r->ombn = i; /* luckily we have one omb per wdsr */
747 wp->dx->ombs[i].stat = 1;
748
749 r->mask = 0;
750 splx(x);
751 smallog3('r', i + '', r->ombn + '');
752 return (r);
753 }
754
755 static void
756 wds_intr(struct wds *wp)
757 {
758 struct wds_req *rp;
759 struct wds_mb *in;
760 u_int8_t stat;
761 u_int8_t c;
762 int addr = wp->addr;
763
764 DBG(DBX "wds%d: interrupt [\n", wp->unit);
765 smallog('[');
766
767 if (inb(addr + WDS_STAT) & WDS_IRQ) {
768 c = inb(addr + WDS_IRQSTAT);
769 if ((c & WDSI_MASK) == WDSI_MSVC) {
770 c = c & ~WDSI_MASK;
771 in = &wp->dx->imbs[c];
772
773 rp = cmdtovirt(wp, scsi_3btoul(in->addr));
774 stat = in->stat;
775
776 if (rp != NULL)
777 wds_done(wp, rp, stat);
778 else
779 device_printf(wp->dev,
780 "got weird command address %p"
781 "from controller\n", rp);
782
783 in->stat = 0;
784 } else
785 device_printf(wp->dev,
786 "weird interrupt, irqstat=0x%x\n", c);
787 outb(addr + WDS_IRQACK, 0);
788 } else {
789 smallog('?');
790 }
791 smallog(']');
792 DBG(DBX "wds%d: ]\n", wp->unit);
793 }
794
795 static void
796 wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat)
797 {
798 struct ccb_hdr *ccb_h;
799 struct ccb_scsiio *csio;
800 int status;
801
802 smallog('d');
803
804 if (r->flags & WR_DONE) {
805 device_printf(wp->dev,
806 "request %d reported done twice\n", r->id);
807 smallog2('x', r->id + '');
808 return;
809 }
810
811 smallog(r->id + '');
812 ccb_h = &r->ccb->ccb_h;
813 csio = &r->ccb->csio;
814 status = CAM_REQ_CMP_ERR;
815
816 DBG(DBX "wds%d: %s stat=0x%x c->stat=0x%x c->venderr=0x%x\n", wp->unit,
817 r->flags & WR_SENSE ? "(sense)" : "",
818 stat, r->cmd.stat, r->cmd.venderr);
819
820 if (r->flags & WR_SENSE) {
821 if (stat == ICMB_OK || (stat == ICMB_OKERR && r->cmd.stat == 0)) {
822 DBG(DBX "wds%d: sense 0x%x\n", wp->unit, r->buf[0]);
823 /* it has the same size now but for future */
824 bcopy(r->buf, &csio->sense_data,
825 sizeof(struct scsi_sense_data) > csio->sense_len ?
826 csio->sense_len : sizeof(struct scsi_sense_data));
827 if (sizeof(struct scsi_sense_data) >= csio->sense_len)
828 csio->sense_resid = 0;
829 else
830 csio->sense_resid =
831 csio->sense_len
832 - sizeof(struct scsi_sense_data);
833 status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR;
834 } else {
835 status = CAM_AUTOSENSE_FAIL;
836 }
837 } else {
838 switch (stat) {
839 case ICMB_OK:
840 if (ccb_h) {
841 csio->resid = 0;
842 csio->scsi_status = r->cmd.stat;
843 status = CAM_REQ_CMP;
844 }
845 break;
846 case ICMB_OKERR:
847 if (ccb_h) {
848 csio->scsi_status = r->cmd.stat;
849 if (r->cmd.stat) {
850 if (ccb_h->flags & CAM_DIS_AUTOSENSE)
851 status = CAM_SCSI_STATUS_ERROR;
852 else {
853 if ( wds_runsense(wp, r) == CAM_REQ_CMP )
854 return;
855 /* in case of error continue with freeing of CCB */
856 }
857 } else {
858 csio->resid = 0;
859 status = CAM_REQ_CMP;
860 }
861 }
862 break;
863 case ICMB_ETIME:
864 if (ccb_h)
865 status = CAM_SEL_TIMEOUT;
866 break;
867 case ICMB_ERESET:
868 case ICMB_ETARCMD:
869 case ICMB_ERESEL:
870 case ICMB_ESEL:
871 case ICMB_EABORT:
872 case ICMB_ESRESET:
873 case ICMB_EHRESET:
874 if (ccb_h)
875 status = CAM_REQ_CMP_ERR;
876 break;
877 }
878
879 if (ccb_h && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) {
880 /* we accept only virtual addresses in wds_action() */
881 bcopy(r->buf, csio->data_ptr, csio->dxfer_len);
882 }
883 }
884
885 r->flags |= WR_DONE;
886 wp->dx->ombs[r->ombn].stat = 0;
887
888 if (ccb_h) {
889 wdsr_ccb_done(wp, r, r->ccb, status);
890 smallog3('-', ccb_h->target_id + '', ccb_h->target_lun + '');
891 } else {
892 frag_free(wp, r->mask);
893 if (wp->want_wdsr) {
894 wp->want_wdsr = 0;
895 xpt_release_simq(wp->sim, /* run queue */ 1);
896 }
897 wp->wdsr_free |= (1 << r->id);
898 }
899
900 DBG(DBX "wds%d: request %p done\n", wp->unit, r);
901 }
902
903 /* command returned bad status, request sense */
904
905 static int
906 wds_runsense(struct wds *wp, struct wds_req *r)
907 {
908 u_int8_t c;
909 struct ccb_hdr *ccb_h;
910
911 ccb_h = &r->ccb->ccb_h;
912
913 r->flags |= WR_SENSE;
914 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd),
915 wp->dx->ombs[r->ombn].addr);
916 bzero(&r->cmd, sizeof r->cmd);
917 r->cmd.cmd = WDSX_SCSICMD;
918 r->cmd.targ = (ccb_h->target_id << 5) |
919 ccb_h->target_lun;
920
921 scsi_ulto3b(0, r->cmd.next);
922
923 r->cmd.scb[0] = REQUEST_SENSE;
924 r->cmd.scb[1] = ccb_h->target_lun << 5;
925 r->cmd.scb[4] = sizeof(struct scsi_sense_data);
926 r->cmd.scb[5] = 0;
927 scsi_ulto3b(WDSTOPHYS(wp, r->buf), r->cmd.data);
928 scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len);
929 r->cmd.write = 0x80;
930
931 outb(wp->addr + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
932
933 wp->dx->ombs[r->ombn].stat = 1;
934 c = WDSC_MSTART(r->ombn);
935
936 if (wds_cmd(wp->addr, &c, sizeof c) != 0) {
937 device_printf(wp->dev, "unable to start outgoing sense mbox\n");
938 wp->dx->ombs[r->ombn].stat = 0;
939 wdsr_ccb_done(wp, r, r->ccb, CAM_AUTOSENSE_FAIL);
940 return CAM_AUTOSENSE_FAIL;
941 } else {
942 DBG(DBX "wds%d: enqueued status cmd 0x%x, r=%p\n",
943 wp->unit, r->cmd.scb[0] & 0xFF, r);
944 /* don't free CCB yet */
945 smallog3('*', ccb_h->target_id + '',
946 ccb_h->target_lun + '');
947 return CAM_REQ_CMP;
948 }
949 }
950
951 static int
952 wds_getvers(struct wds *wp)
953 {
954 struct wds_req *r;
955 int base;
956 u_int8_t c;
957 int i;
958
959 base = wp->addr;
960
961 r = wdsr_alloc(wp);
962 if (!r) {
963 device_printf(wp->dev, "no request slot available!\n");
964 return (-1);
965 }
966 r->flags &= ~WR_DONE;
967
968 r->ccb = NULL;
969
970 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr);
971
972 bzero(&r->cmd, sizeof r->cmd);
973 r->cmd.cmd = WDSX_GETFIRMREV;
974
975 outb(base + WDS_HCR, WDSH_DRQEN);
976
977 c = WDSC_MSTART(r->ombn);
978 if (wds_cmd(base, (u_int8_t *) & c, sizeof c)) {
979 device_printf(wp->dev, "version request failed\n");
980 wp->wdsr_free |= (1 << r->id);
981 wp->dx->ombs[r->ombn].stat = 0;
982 return (-1);
983 }
984 while (1) {
985 i = 0;
986 while ((inb(base + WDS_STAT) & WDS_IRQ) == 0) {
987 DELAY(9000);
988 if (++i == 100) {
989 device_printf(wp->dev, "getvers timeout\n");
990 return (-1);
991 }
992 }
993 wds_intr(wp);
994 if (r->flags & WR_DONE) {
995 device_printf(wp->dev, "firmware version %d.%02d\n",
996 r->cmd.targ, r->cmd.scb[0]);
997 wp->wdsr_free |= (1 << r->id);
998 return (0);
999 }
1000 }
1001 }
1002
1003 static void
1004 wdsr_ccb_done(struct wds *wp, struct wds_req *r,
1005 union ccb *ccb, u_int32_t status)
1006 {
1007 ccb->ccb_h.ccb_wdsr = 0;
1008
1009 if (r != NULL) {
1010 /* To implement timeouts we would need to know how to abort the
1011 * command on controller, and this is a great mystery.
1012 * So for now we just pass the responsibility for timeouts
1013 * to the controlles itself, it does that reasonably good.
1014 */
1015 /* untimeout(_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch); */
1016 /* we're about to free a hcb, so the shortage has ended */
1017 frag_free(wp, r->mask);
1018 if (wp->want_wdsr && status != CAM_REQUEUE_REQ) {
1019 wp->want_wdsr = 0;
1020 status |= CAM_RELEASE_SIMQ;
1021 smallog('R');
1022 }
1023 wp->wdsr_free |= (1 << r->id);
1024 }
1025 ccb->ccb_h.status =
1026 status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED));
1027 xpt_done(ccb);
1028 }
1029
1030 static void
1031 wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio)
1032 {
1033 int unit = cam_sim_unit(sim);
1034 struct wds *wp;
1035 struct ccb_hdr *ccb_h;
1036 struct wds_req *r;
1037 int base;
1038 u_int8_t c;
1039 int error;
1040 int n;
1041
1042 wp = (struct wds *)cam_sim_softc(sim);
1043 ccb_h = &csio->ccb_h;
1044
1045 DBG(DBX "wds%d: cmd TARG=%d LUN=%d\n", unit, ccb_h->target_id,
1046 ccb_h->target_lun);
1047
1048 if (ccb_h->target_id > 7 || ccb_h->target_id == WDS_HBA_ID) {
1049 ccb_h->status = CAM_TID_INVALID;
1050 xpt_done((union ccb *) csio);
1051 return;
1052 }
1053 if (ccb_h->target_lun > 7) {
1054 ccb_h->status = CAM_LUN_INVALID;
1055 xpt_done((union ccb *) csio);
1056 return;
1057 }
1058 if (csio->dxfer_len > BUFSIZ) {
1059 ccb_h->status = CAM_REQ_TOO_BIG;
1060 xpt_done((union ccb *) csio);
1061 return;
1062 }
1063 if (ccb_h->flags & (CAM_CDB_PHYS | CAM_SCATTER_VALID | CAM_DATA_PHYS)) {
1064 /* don't support these */
1065 ccb_h->status = CAM_REQ_INVALID;
1066 xpt_done((union ccb *) csio);
1067 return;
1068 }
1069 base = wp->addr;
1070
1071 /*
1072 * this check is mostly for debugging purposes,
1073 * "can't happen" normally.
1074 */
1075 if(wp->want_wdsr) {
1076 DBG(DBX "wds%d: someone already waits for buffer\n", unit);
1077 smallog('b');
1078 n = xpt_freeze_simq(sim, /* count */ 1);
1079 smallog(''+n);
1080 ccb_h->status = CAM_REQUEUE_REQ;
1081 xpt_done((union ccb *) csio);
1082 return;
1083 }
1084
1085 r = wdsr_alloc(wp);
1086 if (r == NULL) {
1087 device_printf(wp->dev, "no request slot available!\n");
1088 wp->want_wdsr = 1;
1089 n = xpt_freeze_simq(sim, /* count */ 1);
1090 smallog2('f', ''+n);
1091 ccb_h->status = CAM_REQUEUE_REQ;
1092 xpt_done((union ccb *) csio);
1093 return;
1094 }
1095
1096 ccb_h->ccb_wdsr = (void *) r;
1097 r->ccb = (union ccb *) csio;
1098
1099 switch (error = frag_alloc(wp, csio->dxfer_len, &r->buf, &r->mask)) {
1100 case CAM_REQ_CMP:
1101 break;
1102 case CAM_REQUEUE_REQ:
1103 DBG(DBX "wds%d: no data buffer available\n", unit);
1104 wp->want_wdsr = 1;
1105 n = xpt_freeze_simq(sim, /* count */ 1);
1106 smallog2('f', ''+n);
1107 wdsr_ccb_done(wp, r, r->ccb, CAM_REQUEUE_REQ);
1108 return;
1109 default:
1110 DBG(DBX "wds%d: request is too big\n", unit);
1111 wdsr_ccb_done(wp, r, r->ccb, error);
1112 break;
1113 }
1114
1115 ccb_h->status |= CAM_SIM_QUEUED;
1116 r->flags &= ~WR_DONE;
1117
1118 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr);
1119
1120 bzero(&r->cmd, sizeof r->cmd);
1121 r->cmd.cmd = WDSX_SCSICMD;
1122 r->cmd.targ = (ccb_h->target_id << 5) | ccb_h->target_lun;
1123
1124 if (ccb_h->flags & CAM_CDB_POINTER)
1125 bcopy(csio->cdb_io.cdb_ptr, &r->cmd.scb,
1126 csio->cdb_len < 12 ? csio->cdb_len : 12);
1127 else
1128 bcopy(csio->cdb_io.cdb_bytes, &r->cmd.scb,
1129 csio->cdb_len < 12 ? csio->cdb_len : 12);
1130
1131 scsi_ulto3b(csio->dxfer_len, r->cmd.len);
1132
1133 if (csio->dxfer_len > 0
1134 && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
1135 /* we already rejected physical or scattered addresses */
1136 bcopy(csio->data_ptr, r->buf, csio->dxfer_len);
1137 }
1138 scsi_ulto3b(csio->dxfer_len ? WDSTOPHYS(wp, r->buf) : 0, r->cmd.data);
1139
1140 if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
1141 r->cmd.write = 0x80;
1142 else
1143 r->cmd.write = 0x00;
1144
1145 scsi_ulto3b(0, r->cmd.next);
1146
1147 outb(base + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
1148
1149 c = WDSC_MSTART(r->ombn);
1150
1151 if (wds_cmd(base, &c, sizeof c) != 0) {
1152 device_printf(wp->dev, "unable to start outgoing mbox\n");
1153 wp->dx->ombs[r->ombn].stat = 0;
1154 wdsr_ccb_done(wp, r, r->ccb, CAM_RESRC_UNAVAIL);
1155 return;
1156 }
1157 DBG(DBX "wds%d: enqueued cmd 0x%x, r=%p\n", unit,
1158 r->cmd.scb[0] & 0xFF, r);
1159
1160 smallog3('+', ccb_h->target_id + '', ccb_h->target_lun + '');
1161 }
1162
1163 static void
1164 wds_action(struct cam_sim * sim, union ccb * ccb)
1165 {
1166 int unit = cam_sim_unit(sim);
1167 int s;
1168
1169 DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code);
1170 switch (ccb->ccb_h.func_code) {
1171 case XPT_SCSI_IO:
1172 s = splcam();
1173 DBG(DBX "wds%d: SCSI IO entered\n", unit);
1174 wds_scsi_io(sim, &ccb->csio);
1175 DBG(DBX "wds%d: SCSI IO returned\n", unit);
1176 splx(s);
1177 break;
1178 case XPT_RESET_BUS:
1179 /* how to do it right ? */
1180 printf("wds%d: reset\n", unit);
1181 ccb->ccb_h.status = CAM_REQ_CMP;
1182 xpt_done(ccb);
1183 break;
1184 case XPT_ABORT:
1185 ccb->ccb_h.status = CAM_UA_ABORT;
1186 xpt_done(ccb);
1187 break;
1188 case XPT_CALC_GEOMETRY:
1189 {
1190 struct ccb_calc_geometry *ccg;
1191 u_int32_t size_mb;
1192 u_int32_t secs_per_cylinder;
1193
1194 ccg = &ccb->ccg;
1195 size_mb = ccg->volume_size
1196 / ((1024L * 1024L) / ccg->block_size);
1197
1198 ccg->heads = 64;
1199 ccg->secs_per_track = 16;
1200 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
1201 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
1202 ccb->ccb_h.status = CAM_REQ_CMP;
1203 xpt_done(ccb);
1204 break;
1205 }
1206 case XPT_PATH_INQ: /* Path routing inquiry */
1207 {
1208 struct ccb_pathinq *cpi = &ccb->cpi;
1209
1210 cpi->version_num = 1; /* XXX??? */
1211 cpi->hba_inquiry = 0; /* nothing fancy */
1212 cpi->target_sprt = 0;
1213 cpi->hba_misc = 0;
1214 cpi->hba_eng_cnt = 0;
1215 cpi->max_target = 7;
1216 cpi->max_lun = 7;
1217 cpi->initiator_id = WDS_HBA_ID;
1218 cpi->hba_misc = 0;
1219 cpi->bus_id = cam_sim_bus(sim);
1220 cpi->base_transfer_speed = 3300;
1221 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1222 strncpy(cpi->hba_vid, "WD/FDC", HBA_IDLEN);
1223 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1224 cpi->unit_number = cam_sim_unit(sim);
1225 cpi->ccb_h.status = CAM_REQ_CMP;
1226 xpt_done(ccb);
1227 break;
1228 }
1229 default:
1230 ccb->ccb_h.status = CAM_REQ_INVALID;
1231 xpt_done(ccb);
1232 break;
1233 }
1234 }
1235
1236 static void
1237 wds_poll(struct cam_sim * sim)
1238 {
1239 wds_intr((struct wds *)cam_sim_softc(sim));
1240 }
1241
1242 /* part of initialization done in probe() */
1243 /* returns 0 if OK, ENXIO if bad */
1244
1245 static int
1246 wds_preinit(struct wds *wp)
1247 {
1248 int base;
1249 int i;
1250
1251 base = wp->addr;
1252
1253 /*
1254 * Sending a command causes the CMDRDY bit to clear.
1255 */
1256 outb(base + WDS_CMD, WDSC_NOOP);
1257 if (inb(base + WDS_STAT) & WDS_RDY)
1258 return (ENXIO);
1259
1260 /*
1261 * the controller exists. reset and init.
1262 */
1263 outb(base + WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET);
1264 DELAY(30);
1265 outb(base + WDS_HCR, 0);
1266
1267 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
1268 for (i = 0; i < 10; i++) {
1269 if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY)
1270 break;
1271 DELAY(40000);
1272 }
1273 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY)
1274 /* probe timeout */
1275 return (ENXIO);
1276 }
1277
1278 return (0);
1279 }
1280
1281 /* part of initialization done in attach() */
1282 /* returns 0 if OK, 1 if bad */
1283
1284 static int
1285 wds_init(struct wds *wp)
1286 {
1287 struct wds_setup init;
1288 int base;
1289 int i;
1290 struct wds_cmd wc;
1291
1292 base = wp->addr;
1293
1294 outb(base + WDS_HCR, WDSH_DRQEN);
1295
1296 isa_dmacascade(wp->drq);
1297
1298 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
1299 for (i = 0; i < 10; i++) {
1300 if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY)
1301 break;
1302 DELAY(40000);
1303 }
1304 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY)
1305 /* probe timeout */
1306 return (1);
1307 }
1308 bzero(&init, sizeof init);
1309 init.cmd = WDSC_INIT;
1310 init.scsi_id = WDS_HBA_ID;
1311 init.buson_t = 24;
1312 init.busoff_t = 48;
1313 scsi_ulto3b(WDSTOPHYS(wp, &wp->dx->ombs), init.mbaddr);
1314 init.xx = 0;
1315 init.nomb = WDS_NOMB;
1316 init.nimb = WDS_NIMB;
1317
1318 wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
1319 if (wds_cmd(base, (u_int8_t *) & init, sizeof init) != 0) {
1320 device_printf(wp->dev, "wds_cmd init failed\n");
1321 return (1);
1322 }
1323 wds_wait(base + WDS_STAT, WDS_INIT, WDS_INIT);
1324
1325 wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
1326
1327 bzero(&wc, sizeof wc);
1328 wc.cmd = WDSC_DISUNSOL;
1329 if (wds_cmd(base, (char *) &wc, sizeof wc) != 0) {
1330 device_printf(wp->dev, "wds_cmd init2 failed\n");
1331 return (1);
1332 }
1333 return (0);
1334 }
1335
1336 static int
1337 wds_cmd(int base, u_int8_t * p, int l)
1338 {
1339 int s = splcam();
1340
1341 while (l--) {
1342 do {
1343 outb(base + WDS_CMD, *p);
1344 wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
1345 } while (inb(base + WDS_STAT) & WDS_REJ);
1346 p++;
1347 }
1348
1349 wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
1350
1351 splx(s);
1352
1353 return (0);
1354 }
1355
1356 static void
1357 wds_wait(int reg, int mask, int val)
1358 {
1359 while ((inb(reg) & mask) != val)
1360 ;
1361 }
1362
1363 static struct wds_req *
1364 cmdtovirt(struct wds *wp, u_int32_t phys)
1365 {
1366 char *a;
1367
1368 a = WDSTOVIRT(wp, (uintptr_t)phys);
1369 if( a < (char *)&wp->dx->req[0] || a>= (char *)&wp->dx->req[MAXSIMUL]) {
1370 device_printf(wp->dev, "weird phys address 0x%x\n", phys);
1371 return (NULL);
1372 }
1373 a -= (int)offsetof(struct wds_req, cmd); /* convert cmd to request */
1374 return ((struct wds_req *)a);
1375 }
1376
1377 /* for debugging, print out all the data about the status of devices */
1378 void
1379 wds_print(void)
1380 {
1381 int unit;
1382 int i;
1383 struct wds_req *r;
1384 struct wds *wp;
1385
1386 for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) {
1387 wp = (struct wds *) devclass_get_device(wds_devclass, unit);
1388 if (wp == NULL)
1389 continue;
1390 printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n",
1391 unit, wp->want_wdsr, inb(wp->addr + WDS_STAT) & 0xff,
1392 (inb(wp->addr + WDS_STAT) & WDS_IRQ) ? "ready" : "no",
1393 inb(wp->addr + WDS_IRQSTAT) & 0xff);
1394 for (i = 0; i < MAXSIMUL; i++) {
1395 r = &wp->dx->req[i];
1396 if( wp->wdsr_free & (1 << r->id) ) {
1397 printf("req=%d flg=0x%x ombn=%d ombstat=%d "
1398 "mask=0x%x targ=%d lun=%d cmd=0x%x\n",
1399 i, r->flags, r->ombn,
1400 wp->dx->ombs[r->ombn].stat,
1401 r->mask, r->cmd.targ >> 5,
1402 r->cmd.targ & 7, r->cmd.scb[0]);
1403 }
1404 }
1405 }
1406 }
1407
1408 #if WDS_DEBUG == 2
1409 /* create circular log buffer */
1410 static char *
1411 wds_nextlog(void)
1412 {
1413 int n = logwrite;
1414
1415 if (++logwrite >= NLOGLINES)
1416 logwrite = 0;
1417 if (logread == logwrite)
1418 if (++logread >= NLOGLINES)
1419 logread = 0;
1420 return (wds_log[n]);
1421 }
1422
1423 void
1424 wds_printlog(void)
1425 {
1426 /* print the circular buffer */
1427 int i;
1428
1429 for (i = logread; i != logwrite;) {
1430 printf("%s", wds_log[i]);
1431 if (i == NLOGLINES)
1432 i = 0;
1433 else
1434 i++;
1435 }
1436 }
1437 #endif /* WDS_DEBUG */
Cache object: 2c891a8954e560e8dc89d74adebccc9d
|