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