]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/wds/wd7000.c
This commit was generated by cvs2svn to compensate for changes in r165743,
[FreeBSD/FreeBSD.git] / 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  */
38
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
41
42 /* All bugs are subject to removal without further notice */
43
44 /*
45  * offe 01/07/95
46  * 
47  * This version of the driver _still_ doesn't implement scatter/gather for the
48  * WD7000-FASST2. This is due to the fact that my controller doesn't seem to
49  * support it. That, and the lack of documentation makes it impossible for me
50  * to implement it. What I've done instead is allocated a local buffer,
51  * contiguous buffer big enough to handle the requests. I haven't seen any
52  * read/write bigger than 64k, so I allocate a buffer of 64+16k. The data
53  * that needs to be DMA'd to/from the controller is copied to/from that
54  * buffer before/after the command is sent to the card.
55  * 
56  * SB 03/30/00
57  * 
58  * An intermediate buffer is needed anyway to make sure that the buffer is
59  * located under 16MB, otherwise it's out of reach of ISA cards. I've added
60  * optimizations to allocate space in buffer in fragments.
61  */
62
63 /*
64  * Jumpers: (see The Ref(TM) for more info)
65  * W1/W2 - interrupt selection:
66  *  W1 (1-2) IRQ3, (3-4) IRQ4, (5-6) IRQ5, (7-8) IRQ7, (9-10) IRQ9
67  *  W2 (21-22) IRQ10, (19-20) IRQ11, (17-18) IRQ12, (15-16) IRQ14, (13-14) IRQ15
68  *
69  * W2 - DRQ/DACK selection, DRQ and DACK must be the same:
70  *  (5-6) DRQ5 (11-12) DACK5
71  *  (3-4) DRQ6 (9-10) DACK6
72  *  (1-2) DRQ7 (7-8) DACK7
73  *
74  * W3 - I/O address selection: open pair of pins (OFF) means 1, jumpered (ON) means 0
75  *  pair (1-2) is bit 3, ..., pair (9-10) is bit 7. All the other bits are equal
76  *  to the value 0x300. In bitwise representation that would be:
77  *   0 0 1 1 (9-10) (7-8) (5-6) (3-4) (1-2) 0 0 0
78  *  For example, address 0x3C0, bitwise 1111000000 will be represented as:
79  *   (9-10) OFF, (7-8) OFF, (5-6) ON, (3-4) ON, (1-2) ON
80  * 
81  * W4 - BIOS address: open pair of pins (OFF) means 1, jumpered (ON) means 0
82  *  pair (1-2) is bit 13, ..., pair (7-8) is bit 16. All the other bits are
83  *  equal to the value 0xC0000. In bitwise representation that would be:
84  *   1 1 0 (7-8) (5-6) (3-4) (1-2) 0 0000 0000 0000
85  *  For example, address 0xD8000 will be represented as:
86  *   (7-8) OFF, (5-6) OFF, (3-4) ON, (1-2) ON
87  *
88  * W98 (on newer cards) - BIOS enabled; on older cards just remove the BIOS
89  * chip to disable it
90  * W99 (on newer cards) - ROM size (1-2) OFF, (3-4) ON
91  *
92  * W5 - terminator power
93  *  ON - host supplies term. power
94  *  OFF - target supplies term. power
95  *
96  * W6, W9 - floppy support (a bit cryptic):
97  *  W6 ON, W9 ON - disabled
98  *  W6 OFF, W9 ON - enabled with HardCard only
99  *  W6 OFF, W9 OFF - enabled with no hardCard or Combo
100  *
101  * Default: I/O 0x350, IRQ15, DMA6
102  */
103
104 /*
105  * debugging levels: 
106  * 0 - disabled 
107  * 1 - print debugging messages 
108  * 2 - collect  debugging messages in an internal log buffer which can be 
109  *     printed later by calling wds_printlog from DDB 
110  *
111  * Both kind of logs are heavy and interact significantly with the timing 
112  * of commands, so the observed problems may become invisible if debug 
113  * logging is enabled.
114  * 
115  * The light-weight logging facility may be enabled by defining
116  * WDS_ENABLE_SMALLOG as 1. It has very little overhead and allows observing 
117  * the traces of various race conditions without affectiong them but the log is
118  * quite terse. The small log can be printer from DDB by calling
119  * wds_printsmallog.
120  */
121 #ifndef WDS_DEBUG
122 #define WDS_DEBUG 0
123 #endif
124
125 #ifndef WDS_ENABLE_SMALLOG 
126 #define WDS_ENABLE_SMALLOG 0
127 #endif
128
129 #include <sys/types.h>
130 #include <sys/param.h>
131 #include <sys/systm.h>
132 #include <sys/errno.h>
133 #include <sys/kernel.h>
134 #include <sys/assym.h>
135
136 #include <sys/bio.h>
137 #include <sys/buf.h>
138
139 #include <cam/cam.h>
140 #include <cam/cam_ccb.h>
141 #include <cam/cam_sim.h>
142 #include <cam/cam_xpt_sim.h>
143 #include <cam/cam_debug.h>
144 #include <cam/scsi/scsi_all.h>
145 #include <cam/scsi/scsi_message.h>
146
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 MODULE_DEPEND(wds, isa, 1, 1, 1);
404 MODULE_DEPEND(wds, cam, 1, 1, 1);
405
406 #if WDS_ENABLE_SMALLOG==1
407 #define SMALLOGSIZ      512
408 static char      wds_smallog[SMALLOGSIZ];
409 static char     *wds_smallogp = wds_smallog;
410 static char      wds_smallogover = 0;
411
412 static __inline void
413 smallog(char c)
414 {
415         *wds_smallogp = c;
416         if (++wds_smallogp == &wds_smallog[SMALLOGSIZ]) {
417                 wds_smallogp = wds_smallog;
418                 wds_smallogover = 1;
419         }
420 }
421
422 #define smallog2(a, b)  (smallog(a), smallog(b))
423 #define smallog3(a, b, c)       (smallog(a), smallog(b), smallog(c))
424 #define smallog4(a, b, c, d)    (smallog(a),smallog(b),smallog(c),smallog(d))
425
426 void 
427 wds_printsmallog(void)
428 {
429         int      i;
430         char    *p;
431
432         printf("wds: ");
433         p = wds_smallogover ? wds_smallogp : wds_smallog;
434         i = 0;
435         do {
436                 printf("%c", *p);
437                 if (++p == &wds_smallog[SMALLOGSIZ])
438                         p = wds_smallog;
439                 if (++i == 70) {
440                         i = 0;
441                         printf("\nwds: ");
442                 }
443         } while (p != wds_smallogp);
444         printf("\n");
445 }
446 #else
447 #define smallog(a)
448 #define smallog2(a, b)
449 #define smallog3(a, b, c)
450 #define smallog4(a, b, c, d)
451 #endif                          /* SMALLOG */
452
453 static int
454 wds_probe(device_t dev)
455 {
456         struct  wds *wp;
457         int     error = 0;
458         int     irq;
459
460         /* No pnp support */
461         if (isa_get_vendorid(dev))
462                 return (ENXIO);
463
464         wp = (struct wds *) device_get_softc(dev);
465         wp->unit = device_get_unit(dev);
466         wp->dev = dev;
467
468         wp->addr = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/);
469         if (wp->addr == 0 || wp->addr <0x300
470          || wp->addr > 0x3f8 || wp->addr & 0x7) {
471                 device_printf(dev, "invalid port address 0x%x\n", wp->addr);
472                 return (ENXIO);
473         }
474
475         if (bus_set_resource(dev, SYS_RES_IOPORT, 0, wp->addr, WDS_NPORTS) < 0)
476                 return (ENXIO);
477
478         /* get the DRQ */
479         wp->drq = bus_get_resource_start(dev, SYS_RES_DRQ, 0 /*rid*/);
480         if (wp->drq < 5 || wp->drq > 7) {
481                 device_printf(dev, "invalid DRQ %d\n", wp->drq);
482                 return (ENXIO);
483         }
484
485         /* get the IRQ */
486         irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0 /*rid*/);
487         if (irq < 3) {
488                 device_printf(dev, "invalid IRQ %d\n", irq);
489                 return (ENXIO);
490         }
491
492         wp->port_rid = 0;
493         wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT,  &wp->port_rid,
494                                         /*start*/ 0, /*end*/ ~0,
495                                         /*count*/ 0, RF_ACTIVE);
496         if (wp->port_r == NULL)
497                 return (ENXIO);
498
499         error = wds_preinit(wp);
500
501         /*
502          * We cannot hold resources between probe and
503          * attach as we may never be attached.
504          */
505         wds_free_resources(wp);
506
507         return (error);
508 }
509
510 static int
511 wds_attach(device_t dev)
512 {
513         struct  wds *wp;
514         struct  cam_devq *devq;
515         struct  cam_sim *sim;
516         struct  cam_path *pathp;
517         int     i;
518         int     error = 0;
519
520         wp = (struct wds *)device_get_softc(dev);
521
522         wp->port_rid = 0;
523         wp->port_r = bus_alloc_resource(dev, SYS_RES_IOPORT,  &wp->port_rid,
524                                         /*start*/ 0, /*end*/ ~0,
525                                         /*count*/ 0, RF_ACTIVE);
526         if (wp->port_r == NULL)
527                 return (ENXIO);
528
529         /* We must now release resources on error. */
530
531         wp->drq_rid = 0;
532         wp->drq_r = bus_alloc_resource(dev, SYS_RES_DRQ,  &wp->drq_rid,
533                                        /*start*/ 0, /*end*/ ~0,
534                                        /*count*/ 0, RF_ACTIVE);
535         if (wp->drq_r == NULL)
536                 goto bad;
537
538         wp->intr_rid = 0;
539         wp->intr_r = bus_alloc_resource(dev, SYS_RES_IRQ,  &wp->intr_rid,
540                                         /*start*/ 0, /*end*/ ~0,
541                                         /*count*/ 0, RF_ACTIVE);
542         if (wp->intr_r == NULL)
543                 goto bad;
544         error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY,
545                                (driver_intr_t *)wds_intr, (void *)wp,
546                                &wp->intr_cookie);
547         if (error)
548                 goto bad;
549
550         /* now create the memory buffer */
551         error = bus_dma_tag_create(NULL, /*alignment*/4,
552                                    /*boundary*/0,
553                                    /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
554                                    /*highaddr*/ BUS_SPACE_MAXADDR,
555                                    /*filter*/ NULL, /*filterarg*/ NULL,
556                                    /*maxsize*/ sizeof(* wp->dx),
557                                    /*nsegments*/ 1,
558                                    /*maxsegsz*/ sizeof(* wp->dx), /*flags*/ 0,
559                                    /*lockfunc*/busdma_lock_mutex,
560                                    /*lockarg*/&Giant,
561                                    &wp->bustag);
562         if (error)
563                 goto bad;
564
565         error = bus_dmamem_alloc(wp->bustag, (void **)&wp->dx,
566                                  /*flags*/ 0, &wp->busmap);
567         if (error)
568                 goto bad;
569             
570         bus_dmamap_load(wp->bustag, wp->busmap, (void *)wp->dx,
571                         sizeof(* wp->dx), wds_alloc_callback,
572                         (void *)&wp->dx_p, /*flags*/0);
573
574         /* initialize the wds_req structures on this unit */
575         for(i=0; i<MAXSIMUL; i++)  {
576                 wp->dx->req[i].id = i;
577                 wp->wdsr_free |= 1<<i;
578         }
579
580         /* initialize the memory buffer allocation for this unit */
581         if (BUFSIZ / FRAGSIZ > 32) {
582                 fragsiz = (BUFSIZ / 32) & ~0x01; /* keep it word-aligned */
583                 device_printf(dev, "data buffer fragment size too small.  "
584                               "BUFSIZE / FRAGSIZE must be <= 32\n");
585         } else
586                 fragsiz = FRAGSIZ & ~0x01; /* keep it word-aligned */
587
588         wp->data_free = 0;
589         nfrags = 0;
590         for (i = fragsiz; i <= BUFSIZ; i += fragsiz) {
591                 nfrags++;
592                 wp->data_free = (wp->data_free << 1) | 1;
593         }
594
595         /* complete the hardware initialization */
596         if (wds_init(wp) != 0)
597                 goto bad;
598
599         if (wds_getvers(wp) == -1)
600                 device_printf(dev, "getvers failed\n");
601         device_printf(dev, "using %d bytes / %d frags for dma buffer\n",
602                       BUFSIZ, nfrags);
603
604         devq = cam_simq_alloc(MAXSIMUL);
605         if (devq == NULL)
606                 goto bad;
607
608         sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp,
609                             wp->unit, 1, 1, devq);
610         if (sim == NULL) {
611                 cam_simq_free(devq);
612                 goto bad;
613         }
614         wp->sim = sim;
615
616         if (xpt_bus_register(sim, 0) != CAM_SUCCESS) {
617                 cam_sim_free(sim, /* free_devq */ TRUE);
618                 goto bad;
619         }
620         if (xpt_create_path(&pathp, /* periph */ NULL,
621                             cam_sim_path(sim), CAM_TARGET_WILDCARD,
622                             CAM_LUN_WILDCARD) != CAM_REQ_CMP) {
623                 xpt_bus_deregister(cam_sim_path(sim));
624                 cam_sim_free(sim, /* free_devq */ TRUE);
625                 goto bad;
626         }
627         wp->path = pathp;
628
629         return (0);
630
631 bad:
632         wds_free_resources(wp);
633         if (error)  
634                 return (error);
635         else /* exact error is unknown */
636                 return (ENXIO);
637 }
638
639 /* callback to save the physical address */
640 static void     
641 wds_alloc_callback(void *arg, bus_dma_segment_t *seg,  int nseg, int error)
642 {
643         *(bus_addr_t *)arg = seg[0].ds_addr;
644 }
645
646 static void     
647 wds_free_resources(struct wds *wp)
648 {
649         /* check every resource and free if not zero */
650             
651         /* interrupt handler */
652         if (wp->intr_r) {
653                 bus_teardown_intr(wp->dev, wp->intr_r, wp->intr_cookie);
654                 bus_release_resource(wp->dev, SYS_RES_IRQ, wp->intr_rid,
655                                      wp->intr_r);
656                 wp->intr_r = 0;
657         }
658
659         /* all kinds of memory maps we could have allocated */
660         if (wp->dx_p) {
661                 bus_dmamap_unload(wp->bustag, wp->busmap);
662                 wp->dx_p = 0;
663         }
664         if (wp->dx) { /* wp->busmap may be legitimately equal to 0 */
665                 /* the map will also be freed */
666                 bus_dmamem_free(wp->bustag, wp->dx, wp->busmap);
667                 wp->dx = 0;
668         }
669         if (wp->bustag) {
670                 bus_dma_tag_destroy(wp->bustag);
671                 wp->bustag = 0;
672         }
673         /* release all the bus resources */
674         if (wp->drq_r) {
675                 bus_release_resource(wp->dev, SYS_RES_DRQ,
676                                      wp->drq_rid, wp->drq_r);
677                 wp->drq_r = 0;
678         }
679         if (wp->port_r) {
680                 bus_release_resource(wp->dev, SYS_RES_IOPORT,
681                                      wp->port_rid, wp->port_r);
682                 wp->port_r = 0;
683         }
684 }
685
686 /* allocate contiguous fragments from the buffer */
687 static u_int32_t
688 frag_alloc(struct wds *wp, int size, u_int8_t **res, u_int32_t *maskp)
689 {
690         int     i;
691         u_int32_t       mask;
692         u_int32_t       free;
693
694         if (size > fragsiz * nfrags)
695                 return (CAM_REQ_TOO_BIG);
696
697         mask = 1;               /* always allocate at least 1 fragment */
698         for (i = fragsiz; i < size; i += fragsiz)
699                 mask = (mask << 1) | 1;
700
701         free = wp->data_free;
702         if(free != 0) {
703                 i = ffs(free)-1; /* ffs counts bits from 1 */
704                 for (mask <<= i; i < nfrags; i++) {
705                         if ((free & mask) == mask) {
706                                 wp->data_free &= ~mask; /* mark frags as busy */
707                                 *maskp = mask;
708                                 *res = &wp->dx->data[fragsiz * i];
709                                 DBG(DBX "wds%d: allocated buffer mask=0x%x\n",
710                                         wp->unit, mask);
711                                 return (CAM_REQ_CMP);
712                         }
713                         if (mask & 0x80000000)
714                                 break;
715
716                         mask <<= 1;
717                 }
718         }
719         return (CAM_REQUEUE_REQ);       /* no free memory now, try later */
720 }
721
722 static void
723 frag_free(struct wds *wp, u_int32_t mask)
724 {
725         wp->data_free |= mask;  /* mark frags as free */
726         DBG(DBX "wds%d: freed buffer mask=0x%x\n", wp->unit, mask);
727 }
728
729 static struct wds_req *
730 wdsr_alloc(struct wds *wp)
731 {
732         struct  wds_req *r;
733         int     x;
734         int     i;
735
736         r = NULL;
737         x = splcam();
738
739         /* anyway most of the time only 1 or 2 commands will
740          * be active because SCSI disconnect is not supported
741          * by hardware, so the search should be fast enough
742          */
743         i = ffs(wp->wdsr_free) - 1;
744         if(i < 0) {
745                 splx(x);
746                 return (NULL);
747         }
748         wp->wdsr_free &= ~ (1<<i);
749         r = &wp->dx->req[i];
750         r->flags = 0;   /* reset all flags */
751         r->ombn = i;            /* luckily we have one omb per wdsr */
752         wp->dx->ombs[i].stat = 1;
753
754         r->mask = 0;
755         splx(x);
756         smallog3('r', i + '0', r->ombn + '0');
757         return (r);
758 }
759
760 static void
761 wds_intr(struct wds *wp)
762 {
763         struct   wds_req *rp;
764         struct   wds_mb *in;
765         u_int8_t stat;
766         u_int8_t c;
767         int      addr = wp->addr;
768
769         DBG(DBX "wds%d: interrupt [\n", wp->unit);
770         smallog('[');
771
772         if (inb(addr + WDS_STAT) & WDS_IRQ) {
773                 c = inb(addr + WDS_IRQSTAT);
774                 if ((c & WDSI_MASK) == WDSI_MSVC) {
775                         c = c & ~WDSI_MASK;
776                         in = &wp->dx->imbs[c];
777
778                         rp = cmdtovirt(wp, scsi_3btoul(in->addr));
779                         stat = in->stat;
780
781                         if (rp != NULL)
782                                 wds_done(wp, rp, stat);
783                         else
784                                 device_printf(wp->dev,
785                                               "got weird command address %p"
786                                               "from controller\n", rp);
787
788                         in->stat = 0;
789                 } else
790                         device_printf(wp->dev,
791                                       "weird interrupt, irqstat=0x%x\n", c);
792                 outb(addr + WDS_IRQACK, 0);
793         } else {
794                 smallog('?');
795         }
796         smallog(']');
797         DBG(DBX "wds%d: ]\n", wp->unit);
798 }
799
800 static void
801 wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat)
802 {
803         struct  ccb_hdr *ccb_h;
804         struct  ccb_scsiio *csio;
805         int     status;
806
807         smallog('d');
808
809         if (r->flags & WR_DONE) {
810                 device_printf(wp->dev,
811                                 "request %d reported done twice\n", r->id);
812                 smallog2('x', r->id + '0');
813                 return;
814         }
815
816         smallog(r->id + '0');
817         ccb_h = &r->ccb->ccb_h;
818         csio = &r->ccb->csio;
819         status = CAM_REQ_CMP_ERR;
820
821         DBG(DBX "wds%d: %s stat=0x%x c->stat=0x%x c->venderr=0x%x\n", wp->unit,
822             r->flags & WR_SENSE ? "(sense)" : "", 
823                 stat, r->cmd.stat, r->cmd.venderr);
824
825         if (r->flags & WR_SENSE) {
826                 if (stat == ICMB_OK || (stat == ICMB_OKERR && r->cmd.stat == 0)) {
827                         DBG(DBX "wds%d: sense 0x%x\n", wp->unit, r->buf[0]);
828                         /* it has the same size now but for future */
829                         bcopy(r->buf, &csio->sense_data,
830                               sizeof(struct scsi_sense_data) > csio->sense_len ?
831                               csio->sense_len : sizeof(struct scsi_sense_data));
832                         if (sizeof(struct scsi_sense_data) >= csio->sense_len)
833                                 csio->sense_resid = 0;
834                         else
835                                 csio->sense_resid =
836                                         csio->sense_len
837                                       - sizeof(struct scsi_sense_data);
838                         status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR;
839                 } else {
840                         status = CAM_AUTOSENSE_FAIL;
841                 }
842         } else {
843                 switch (stat) {
844                 case ICMB_OK:
845                         if (ccb_h) {
846                                 csio->resid = 0;
847                                 csio->scsi_status = r->cmd.stat;
848                                 status = CAM_REQ_CMP;
849                         }
850                         break;
851                 case ICMB_OKERR:
852                         if (ccb_h) {
853                                 csio->scsi_status = r->cmd.stat;
854                                 if (r->cmd.stat) {
855                                         if (ccb_h->flags & CAM_DIS_AUTOSENSE)
856                                                 status = CAM_SCSI_STATUS_ERROR;
857                                         else {
858                                                 if ( wds_runsense(wp, r) == CAM_REQ_CMP )
859                                                         return;
860                                                 /* in case of error continue with freeing of CCB */
861                                         }
862                                 } else {
863                                         csio->resid = 0;
864                                         status = CAM_REQ_CMP;
865                                 }
866                         }
867                         break;
868                 case ICMB_ETIME:
869                         if (ccb_h)
870                                 status = CAM_SEL_TIMEOUT;
871                         break;
872                 case ICMB_ERESET:
873                 case ICMB_ETARCMD:
874                 case ICMB_ERESEL:
875                 case ICMB_ESEL:
876                 case ICMB_EABORT:
877                 case ICMB_ESRESET:
878                 case ICMB_EHRESET:
879                         if (ccb_h)
880                                 status = CAM_REQ_CMP_ERR;
881                         break;
882                 }
883
884                 if (ccb_h && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) {
885                         /* we accept only virtual addresses in wds_action() */
886                         bcopy(r->buf, csio->data_ptr, csio->dxfer_len);
887                 }
888         }
889
890         r->flags |= WR_DONE;
891         wp->dx->ombs[r->ombn].stat = 0;
892
893         if (ccb_h) {
894                 wdsr_ccb_done(wp, r, r->ccb, status);
895                 smallog3('-', ccb_h->target_id + '0', ccb_h->target_lun + '0');
896         } else {
897                 frag_free(wp, r->mask);
898                 if (wp->want_wdsr) {
899                         wp->want_wdsr = 0;
900                         xpt_release_simq(wp->sim, /* run queue */ 1);
901                 }
902                 wp->wdsr_free |= (1 << r->id);
903         }
904
905         DBG(DBX "wds%d: request %p done\n", wp->unit, r);
906 }
907
908 /* command returned bad status, request sense */
909
910 static int
911 wds_runsense(struct wds *wp, struct wds_req *r)
912 {
913         u_int8_t          c;
914         struct  ccb_hdr *ccb_h;
915
916         ccb_h = &r->ccb->ccb_h;
917
918         r->flags |= WR_SENSE;
919         scsi_ulto3b(WDSTOPHYS(wp, &r->cmd),
920          wp->dx->ombs[r->ombn].addr);
921         bzero(&r->cmd, sizeof r->cmd);
922         r->cmd.cmd = WDSX_SCSICMD;
923         r->cmd.targ = (ccb_h->target_id << 5) |
924                 ccb_h->target_lun;
925
926         scsi_ulto3b(0, r->cmd.next);
927
928         r->cmd.scb[0] = REQUEST_SENSE;
929         r->cmd.scb[1] = ccb_h->target_lun << 5;
930         r->cmd.scb[4] = sizeof(struct scsi_sense_data);
931         r->cmd.scb[5] = 0;
932         scsi_ulto3b(WDSTOPHYS(wp, r->buf), r->cmd.data);
933         scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len);
934         r->cmd.write = 0x80;
935
936         outb(wp->addr + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
937
938         wp->dx->ombs[r->ombn].stat = 1;
939         c = WDSC_MSTART(r->ombn);
940
941         if (wds_cmd(wp->addr, &c, sizeof c) != 0) {
942                 device_printf(wp->dev, "unable to start outgoing sense mbox\n");
943                 wp->dx->ombs[r->ombn].stat = 0;
944                 wdsr_ccb_done(wp, r, r->ccb, CAM_AUTOSENSE_FAIL);
945                 return CAM_AUTOSENSE_FAIL;
946         } else {
947                 DBG(DBX "wds%d: enqueued status cmd 0x%x, r=%p\n",
948                         wp->unit, r->cmd.scb[0] & 0xFF, r);
949                 /* don't free CCB yet */
950                 smallog3('*', ccb_h->target_id + '0',
951                          ccb_h->target_lun + '0');
952                 return CAM_REQ_CMP;
953         }
954 }
955
956 static int
957 wds_getvers(struct wds *wp)
958 {
959         struct   wds_req *r;
960         int      base;
961         u_int8_t c;
962         int      i;
963
964         base = wp->addr;
965
966         r = wdsr_alloc(wp);
967         if (!r) {
968                 device_printf(wp->dev, "no request slot available!\n");
969                 return (-1);
970         }
971         r->flags &= ~WR_DONE;
972
973         r->ccb = NULL;
974
975         scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr);
976
977         bzero(&r->cmd, sizeof r->cmd);
978         r->cmd.cmd = WDSX_GETFIRMREV;
979
980         outb(base + WDS_HCR, WDSH_DRQEN);
981
982         c = WDSC_MSTART(r->ombn);
983         if (wds_cmd(base, (u_int8_t *) & c, sizeof c)) {
984                 device_printf(wp->dev, "version request failed\n");
985                 wp->wdsr_free |= (1 << r->id);
986                 wp->dx->ombs[r->ombn].stat = 0;
987                 return (-1);
988         }
989         while (1) {
990                 i = 0;
991                 while ((inb(base + WDS_STAT) & WDS_IRQ) == 0) {
992                         DELAY(9000);
993                         if (++i == 100) {
994                                 device_printf(wp->dev, "getvers timeout\n");
995                                 return (-1);
996                         }
997                 }
998                 wds_intr(wp);
999                 if (r->flags & WR_DONE) {
1000                         device_printf(wp->dev, "firmware version %d.%02d\n",
1001                                r->cmd.targ, r->cmd.scb[0]);
1002                         wp->wdsr_free |= (1 << r->id);
1003                         return (0);
1004                 }
1005         }
1006 }
1007
1008 static void
1009 wdsr_ccb_done(struct wds *wp, struct wds_req *r,
1010               union ccb *ccb, u_int32_t status)
1011 {
1012         ccb->ccb_h.ccb_wdsr = 0;
1013
1014         if (r != NULL) {
1015                 /* To implement timeouts we would need to know how to abort the
1016                  * command on controller, and this is a great mystery.
1017                  * So for now we just pass the responsibility for timeouts
1018                  * to the controlles itself, it does that reasonably good.
1019                  */
1020                 /* untimeout(_timeout, (caddr_t) hcb, ccb->ccb_h.timeout_ch); */
1021                 /* we're about to free a hcb, so the shortage has ended */
1022                 frag_free(wp, r->mask);
1023                 if (wp->want_wdsr && status != CAM_REQUEUE_REQ) {
1024                         wp->want_wdsr = 0;
1025                         status |= CAM_RELEASE_SIMQ;
1026                         smallog('R');
1027                 }
1028                 wp->wdsr_free |= (1 << r->id);
1029         }
1030         ccb->ccb_h.status =
1031             status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED));
1032         xpt_done(ccb);
1033 }
1034
1035 static void
1036 wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio)
1037 {
1038         int      unit = cam_sim_unit(sim);
1039         struct   wds *wp;
1040         struct   ccb_hdr *ccb_h;
1041         struct   wds_req *r;
1042         int      base;
1043         u_int8_t c;
1044         int      error;
1045         int      n;
1046
1047         wp = (struct wds *)cam_sim_softc(sim);
1048         ccb_h = &csio->ccb_h;
1049
1050         DBG(DBX "wds%d: cmd TARG=%d LUN=%d\n", unit, ccb_h->target_id,
1051             ccb_h->target_lun);
1052
1053         if (ccb_h->target_id > 7 || ccb_h->target_id == WDS_HBA_ID) {
1054                 ccb_h->status = CAM_TID_INVALID;
1055                 xpt_done((union ccb *) csio);
1056                 return;
1057         }
1058         if (ccb_h->target_lun > 7) {
1059                 ccb_h->status = CAM_LUN_INVALID;
1060                 xpt_done((union ccb *) csio);
1061                 return;
1062         }
1063         if (csio->dxfer_len > BUFSIZ) {
1064                 ccb_h->status = CAM_REQ_TOO_BIG;
1065                 xpt_done((union ccb *) csio);
1066                 return;
1067         }
1068         if (ccb_h->flags & (CAM_CDB_PHYS | CAM_SCATTER_VALID | CAM_DATA_PHYS)) {
1069                 /* don't support these */
1070                 ccb_h->status = CAM_REQ_INVALID;
1071                 xpt_done((union ccb *) csio);
1072                 return;
1073         }
1074         base = wp->addr;
1075
1076         /*
1077          * this check is mostly for debugging purposes,
1078          * "can't happen" normally.
1079          */
1080         if(wp->want_wdsr) {
1081                 DBG(DBX "wds%d: someone already waits for buffer\n", unit);
1082                 smallog('b');
1083                 n = xpt_freeze_simq(sim, /* count */ 1);
1084                 smallog('0'+n);
1085                 ccb_h->status = CAM_REQUEUE_REQ;
1086                 xpt_done((union ccb *) csio);
1087                 return;
1088         }
1089
1090         r = wdsr_alloc(wp);
1091         if (r == NULL) {
1092                 device_printf(wp->dev, "no request slot available!\n");
1093                 wp->want_wdsr = 1;
1094                 n = xpt_freeze_simq(sim, /* count */ 1);
1095                 smallog2('f', '0'+n);
1096                 ccb_h->status = CAM_REQUEUE_REQ;
1097                 xpt_done((union ccb *) csio);
1098                 return;
1099         }
1100
1101         ccb_h->ccb_wdsr = (void *) r;
1102         r->ccb = (union ccb *) csio;
1103
1104         switch (error = frag_alloc(wp, csio->dxfer_len, &r->buf, &r->mask)) {
1105         case CAM_REQ_CMP:
1106                 break;
1107         case CAM_REQUEUE_REQ:
1108                 DBG(DBX "wds%d: no data buffer available\n", unit);
1109                 wp->want_wdsr = 1;
1110                 n = xpt_freeze_simq(sim, /* count */ 1);
1111                 smallog2('f', '0'+n);
1112                 wdsr_ccb_done(wp, r, r->ccb, CAM_REQUEUE_REQ);
1113                 return;
1114         default:
1115                 DBG(DBX "wds%d: request is too big\n", unit);
1116                 wdsr_ccb_done(wp, r, r->ccb, error);
1117                 break;
1118         }
1119
1120         ccb_h->status |= CAM_SIM_QUEUED;
1121         r->flags &= ~WR_DONE;
1122
1123         scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr);
1124
1125         bzero(&r->cmd, sizeof r->cmd);
1126         r->cmd.cmd = WDSX_SCSICMD;
1127         r->cmd.targ = (ccb_h->target_id << 5) | ccb_h->target_lun;
1128
1129         if (ccb_h->flags & CAM_CDB_POINTER)
1130                 bcopy(csio->cdb_io.cdb_ptr, &r->cmd.scb,
1131                       csio->cdb_len < 12 ? csio->cdb_len : 12);
1132         else
1133                 bcopy(csio->cdb_io.cdb_bytes, &r->cmd.scb,
1134                       csio->cdb_len < 12 ? csio->cdb_len : 12);
1135
1136         scsi_ulto3b(csio->dxfer_len, r->cmd.len);
1137
1138         if (csio->dxfer_len > 0
1139          && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
1140                 /* we already rejected physical or scattered addresses */
1141                 bcopy(csio->data_ptr, r->buf, csio->dxfer_len);
1142         }
1143         scsi_ulto3b(csio->dxfer_len ? WDSTOPHYS(wp, r->buf) : 0, r->cmd.data);
1144
1145         if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
1146                 r->cmd.write = 0x80;
1147         else
1148                 r->cmd.write = 0x00;
1149
1150         scsi_ulto3b(0, r->cmd.next);
1151
1152         outb(base + WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
1153
1154         c = WDSC_MSTART(r->ombn);
1155
1156         if (wds_cmd(base, &c, sizeof c) != 0) {
1157                 device_printf(wp->dev, "unable to start outgoing mbox\n");
1158                 wp->dx->ombs[r->ombn].stat = 0;
1159                 wdsr_ccb_done(wp, r, r->ccb, CAM_RESRC_UNAVAIL);
1160                 return;
1161         }
1162         DBG(DBX "wds%d: enqueued cmd 0x%x, r=%p\n", unit,
1163             r->cmd.scb[0] & 0xFF, r);
1164
1165         smallog3('+', ccb_h->target_id + '0', ccb_h->target_lun + '0');
1166 }
1167
1168 static void
1169 wds_action(struct cam_sim * sim, union ccb * ccb)
1170 {
1171         int     unit = cam_sim_unit(sim);
1172         int     s;
1173
1174         DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code);
1175         switch (ccb->ccb_h.func_code) {
1176         case XPT_SCSI_IO:
1177                 s = splcam();
1178                 DBG(DBX "wds%d: SCSI IO entered\n", unit);
1179                 wds_scsi_io(sim, &ccb->csio);
1180                 DBG(DBX "wds%d: SCSI IO returned\n", unit);
1181                 splx(s);
1182                 break;
1183         case XPT_RESET_BUS:
1184                 /* how to do it right ? */
1185                 printf("wds%d: reset\n", unit);
1186                 ccb->ccb_h.status = CAM_REQ_CMP;
1187                 xpt_done(ccb);
1188                 break;
1189         case XPT_ABORT:
1190                 ccb->ccb_h.status = CAM_UA_ABORT;
1191                 xpt_done(ccb);
1192                 break;
1193         case XPT_CALC_GEOMETRY:
1194         {
1195                 struct    ccb_calc_geometry *ccg;
1196                 u_int32_t size_mb;
1197                 u_int32_t secs_per_cylinder;
1198
1199                 ccg = &ccb->ccg;
1200                 size_mb = ccg->volume_size
1201                         / ((1024L * 1024L) / ccg->block_size);
1202
1203                 ccg->heads = 64;
1204                 ccg->secs_per_track = 16;
1205                 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
1206                 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
1207                 ccb->ccb_h.status = CAM_REQ_CMP;
1208                 xpt_done(ccb);
1209                 break;
1210         }
1211         case XPT_PATH_INQ:      /* Path routing inquiry */
1212         {
1213                 struct ccb_pathinq *cpi = &ccb->cpi;
1214
1215                 cpi->version_num = 1;   /* XXX??? */
1216                 cpi->hba_inquiry = 0;   /* nothing fancy */
1217                 cpi->target_sprt = 0;
1218                 cpi->hba_misc = 0;
1219                 cpi->hba_eng_cnt = 0;
1220                 cpi->max_target = 7;
1221                 cpi->max_lun = 7;
1222                 cpi->initiator_id = WDS_HBA_ID;
1223                 cpi->hba_misc = 0;
1224                 cpi->bus_id = cam_sim_bus(sim);
1225                 cpi->base_transfer_speed = 3300;
1226                 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1227                 strncpy(cpi->hba_vid, "WD/FDC", HBA_IDLEN);
1228                 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1229                 cpi->unit_number = cam_sim_unit(sim);
1230                 cpi->ccb_h.status = CAM_REQ_CMP;
1231                 xpt_done(ccb);
1232                 break;
1233         }
1234         default:
1235                 ccb->ccb_h.status = CAM_REQ_INVALID;
1236                 xpt_done(ccb);
1237                 break;
1238         }
1239 }
1240
1241 static void
1242 wds_poll(struct cam_sim * sim)
1243 {
1244         wds_intr((struct wds *)cam_sim_softc(sim));
1245 }
1246
1247 /* part of initialization done in probe() */
1248 /* returns 0 if OK, ENXIO if bad */
1249
1250 static int
1251 wds_preinit(struct wds *wp)
1252 {
1253         int     base;
1254         int     i;
1255
1256         base = wp->addr;
1257
1258         /*
1259          * Sending a command causes the CMDRDY bit to clear.
1260          */
1261         outb(base + WDS_CMD, WDSC_NOOP);
1262         if (inb(base + WDS_STAT) & WDS_RDY)
1263                 return (ENXIO);
1264
1265         /*
1266          * the controller exists. reset and init.
1267          */
1268         outb(base + WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET);
1269         DELAY(30);
1270         outb(base + WDS_HCR, 0);
1271
1272         if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
1273                 for (i = 0; i < 10; i++) {
1274                         if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY)
1275                                 break;
1276                         DELAY(40000);
1277                 }
1278                 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY)
1279                         /* probe timeout */
1280                         return (ENXIO);
1281         }
1282
1283         return (0);
1284 }
1285
1286 /* part of initialization done in attach() */
1287 /* returns 0 if OK, 1 if bad */
1288
1289 static int
1290 wds_init(struct wds *wp)
1291 {
1292         struct  wds_setup init;
1293         int     base;
1294         int     i;
1295         struct  wds_cmd  wc;
1296
1297         base = wp->addr;
1298
1299         outb(base + WDS_HCR, WDSH_DRQEN);
1300
1301         isa_dmacascade(wp->drq);
1302
1303         if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
1304                 for (i = 0; i < 10; i++) {
1305                         if ((inb(base + WDS_STAT) & (WDS_RDY)) == WDS_RDY)
1306                                 break;
1307                         DELAY(40000);
1308                 }
1309                 if ((inb(base + WDS_STAT) & (WDS_RDY)) != WDS_RDY)
1310                         /* probe timeout */
1311                         return (1);
1312         }
1313         bzero(&init, sizeof init);
1314         init.cmd = WDSC_INIT;
1315         init.scsi_id = WDS_HBA_ID;
1316         init.buson_t = 24;
1317         init.busoff_t = 48;
1318         scsi_ulto3b(WDSTOPHYS(wp, &wp->dx->ombs), init.mbaddr); 
1319         init.xx = 0;
1320         init.nomb = WDS_NOMB;
1321         init.nimb = WDS_NIMB;
1322
1323         wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
1324         if (wds_cmd(base, (u_int8_t *) & init, sizeof init) != 0) {
1325                 device_printf(wp->dev, "wds_cmd init failed\n");
1326                 return (1);
1327         }
1328         wds_wait(base + WDS_STAT, WDS_INIT, WDS_INIT);
1329
1330         wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
1331
1332         bzero(&wc, sizeof wc);
1333         wc.cmd = WDSC_DISUNSOL;
1334         if (wds_cmd(base, (char *) &wc, sizeof wc) != 0) {
1335                 device_printf(wp->dev, "wds_cmd init2 failed\n");
1336                 return (1);
1337         }
1338         return (0);
1339 }
1340
1341 static int
1342 wds_cmd(int base, u_int8_t * p, int l)
1343 {
1344         int     s = splcam();
1345
1346         while (l--) {
1347                 do {
1348                         outb(base + WDS_CMD, *p);
1349                         wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
1350                 } while (inb(base + WDS_STAT) & WDS_REJ);
1351                 p++;
1352         }
1353
1354         wds_wait(base + WDS_STAT, WDS_RDY, WDS_RDY);
1355
1356         splx(s);
1357
1358         return (0);
1359 }
1360
1361 static void
1362 wds_wait(int reg, int mask, int val)
1363 {
1364         while ((inb(reg) & mask) != val)
1365                 ;
1366 }
1367
1368 static struct wds_req *
1369 cmdtovirt(struct wds *wp, u_int32_t phys)
1370 {
1371         char    *a;
1372
1373         a = WDSTOVIRT(wp, (uintptr_t)phys);
1374         if( a < (char *)&wp->dx->req[0] || a>= (char *)&wp->dx->req[MAXSIMUL]) {
1375                 device_printf(wp->dev, "weird phys address 0x%x\n", phys);
1376                 return (NULL);
1377         }
1378         a -= (int)offsetof(struct wds_req, cmd); /* convert cmd to request */
1379         return ((struct wds_req *)a);
1380 }
1381
1382 /* for debugging, print out all the data about the status of devices */
1383 void
1384 wds_print(void)
1385 {
1386         int     unit;
1387         int     i;
1388         struct  wds_req *r;
1389         struct  wds     *wp;
1390
1391         for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) {
1392                 wp = (struct wds *) devclass_get_device(wds_devclass, unit);
1393                 if (wp == NULL)
1394                         continue;
1395                 printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n",
1396                        unit, wp->want_wdsr, inb(wp->addr + WDS_STAT) & 0xff,
1397                        (inb(wp->addr + WDS_STAT) & WDS_IRQ) ? "ready" : "no",
1398                        inb(wp->addr + WDS_IRQSTAT) & 0xff);
1399                 for (i = 0; i < MAXSIMUL; i++) {
1400                         r = &wp->dx->req[i];
1401                         if( wp->wdsr_free & (1 << r->id) ) {
1402                                 printf("req=%d flg=0x%x ombn=%d ombstat=%d "
1403                                        "mask=0x%x targ=%d lun=%d cmd=0x%x\n",
1404                                        i, r->flags, r->ombn,
1405                                        wp->dx->ombs[r->ombn].stat,
1406                                        r->mask, r->cmd.targ >> 5,
1407                                        r->cmd.targ & 7, r->cmd.scb[0]);
1408                         }
1409                 }
1410         }
1411 }
1412
1413 #if WDS_DEBUG == 2
1414 /* create circular log buffer */
1415 static char    *
1416 wds_nextlog(void)
1417 {
1418         int     n = logwrite;
1419
1420         if (++logwrite >= NLOGLINES)
1421                 logwrite = 0;
1422         if (logread == logwrite)
1423                 if (++logread >= NLOGLINES)
1424                         logread = 0;
1425         return (wds_log[n]);
1426 }
1427
1428 void
1429 wds_printlog(void)
1430 {
1431         /* print the circular buffer */
1432         int     i;
1433
1434         for (i = logread; i != logwrite;) {
1435                 printf("%s", wds_log[i]);
1436                 if (i == NLOGLINES)
1437                         i = 0;
1438                 else
1439                         i++;
1440         }
1441 }
1442 #endif /* WDS_DEBUG */