2 * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
3 * Copyright (c) 2000 Sergey A. Babkin
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>.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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
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.
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
42 /* All bugs are subject to removal without further notice */
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.
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.
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
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
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
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
88 * W98 (on newer cards) - BIOS enabled; on older cards just remove the BIOS
90 * W99 (on newer cards) - ROM size (1-2) OFF, (3-4) ON
92 * W5 - terminator power
93 * ON - host supplies term. power
94 * OFF - target supplies term. power
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
101 * Default: I/O 0x350, IRQ15, DMA6
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
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.
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
125 #ifndef WDS_ENABLE_SMALLOG
126 #define WDS_ENABLE_SMALLOG 0
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 #include <sys/malloc.h>
141 #include <cam/cam_ccb.h>
142 #include <cam/cam_sim.h>
143 #include <cam/cam_xpt_sim.h>
144 #include <cam/cam_debug.h>
145 #include <cam/scsi/scsi_all.h>
146 #include <cam/scsi/scsi_message.h>
150 #include <vm/vm_param.h>
153 #include <sys/module.h>
155 #include <machine/bus.h>
156 #include <machine/resource.h>
157 #include <sys/rman.h>
159 #include <isa/isavar.h>
160 #include <isa/pnpvar.h>
162 #define WDSTOPHYS(wp, a) ( ((uintptr_t)a) - ((uintptr_t)wp->dx) + (wp->dx_p) )
163 #define WDSTOVIRT(wp, a) ( ((a) - (wp->dx_p)) + ((char *)wp->dx) )
165 /* 0x10000 (64k) should be enough. But just to be sure... */
166 #define BUFSIZ 0x12000
167 /* buffer fragment size, no more than 32 frags per buffer */
168 #define FRAGSIZ 0x1000
171 /* WD7000 registers */
172 #define WDS_STAT 0 /* read */
173 #define WDS_IRQSTAT 1 /* read */
175 #define WDS_CMD 0 /* write */
176 #define WDS_IRQACK 1 /* write */
177 #define WDS_HCR 2 /* write */
179 #define WDS_NPORTS 4 /* number of ports used */
181 /* WDS_STAT (read) defs */
185 #define WDS_INIT 0x10
187 /* WDS_IRQSTAT (read) defs */
188 #define WDSI_MASK 0xc0
189 #define WDSI_ERR 0x00
190 #define WDSI_MFREE 0x80
191 #define WDSI_MSVC 0xc0
193 /* WDS_CMD (write) defs */
194 #define WDSC_NOOP 0x00
195 #define WDSC_INIT 0x01
196 #define WDSC_DISUNSOL 0x02 /* disable unsolicited ints */
197 #define WDSC_ENAUNSOL 0x03 /* enable unsolicited ints */
198 #define WDSC_IRQMFREE 0x04 /* interrupt on free RQM */
199 #define WDSC_SCSIRESETSOFT 0x05 /* soft reset */
200 #define WDSC_SCSIRESETHARD 0x06 /* hard reset ack */
201 #define WDSC_MSTART(m) (0x80 + (m)) /* start mailbox */
202 #define WDSC_MMSTART(m) (0xc0 + (m)) /* start all mailboxes */
204 /* WDS_HCR (write) defs */
205 #define WDSH_IRQEN 0x08
206 #define WDSH_DRQEN 0x04
207 #define WDSH_SCSIRESET 0x02
208 #define WDSH_ASCRESET 0x01
230 u_int8_t *buf; /* address of linear data buffer */
231 u_int32_t mask; /* mask of allocated fragments */
233 u_int8_t id; /* number of request */
236 #define WDSX_SCSICMD 0x00
237 #define WDSX_OPEN_RCVBUF 0x80
238 #define WDSX_RCV_CMD 0x81
239 #define WDSX_RCV_DATA 0x82
240 #define WDSX_RCV_DATASTAT 0x83
241 #define WDSX_SND_DATA 0x84
242 #define WDSX_SND_DATASTAT 0x85
243 #define WDSX_SND_CMDSTAT 0x86
244 #define WDSX_READINIT 0x88
245 #define WDSX_READSCSIID 0x89
246 #define WDSX_SETUNSOLIRQMASK 0x8a
247 #define WDSX_GETUNSOLIRQMASK 0x8b
248 #define WDSX_GETFIRMREV 0x8c
249 #define WDSX_EXECDIAG 0x8d
250 #define WDSX_SETEXECPARM 0x8e
251 #define WDSX_GETEXECPARM 0x8f
257 /* ICMB status value */
259 #define ICMB_OKERR 0x02
260 #define ICMB_ETIME 0x04
261 #define ICMB_ERESET 0x05
262 #define ICMB_ETARCMD 0x06
263 #define ICMB_ERESEL 0x80
264 #define ICMB_ESEL 0x81
265 #define ICMB_EABORT 0x82
266 #define ICMB_ESRESET 0x83
267 #define ICMB_EHRESET 0x84
280 /* the code depends on equality of these parameters */
282 #define WDS_NOMB MAXSIMUL
283 #define WDS_NIMB MAXSIMUL
288 /* structure for data exchange with controller */
291 struct wds_req req[MAXSIMUL];
292 struct wds_mb ombs[MAXSIMUL];
293 struct wds_mb imbs[MAXSIMUL];
294 u_int8_t data[BUFSIZ];
297 /* structure softc */
304 struct cam_sim *sim; /* SIM descriptor for this card */
305 struct cam_path *path; /* wildcard path for this card */
306 char want_wdsr; /* resource shortage flag */
310 bus_addr_t dx_p; /* physical address */
311 struct resource *port_r;
313 struct resource *drq_r;
315 struct resource *intr_r;
318 bus_dma_tag_t bustag;
322 #define ccb_wdsr spriv_ptr1 /* for wds request */
324 static int wds_probe(device_t dev);
325 static int wds_attach(device_t dev);
326 static void wds_intr(void *arg);
327 static void wds_intr_locked(struct wds *wp);
329 static void wds_action(struct cam_sim * sim, union ccb * ccb);
330 static void wds_poll(struct cam_sim * sim);
332 static int wds_preinit(struct wds *wp);
333 static int wds_init(struct wds *wp);
335 static void wds_alloc_callback(void *arg, bus_dma_segment_t *seg,
336 int nseg, int error);
337 static void wds_free_resources(struct wds *wp);
339 static struct wds_req *wdsr_alloc(struct wds *wp);
341 static void wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio);
342 static void wdsr_ccb_done(struct wds *wp, struct wds_req *r,
343 union ccb *ccb, u_int32_t status);
345 static void wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat);
346 static int wds_runsense(struct wds *wp, struct wds_req *r);
347 static int wds_getvers(struct wds *wp);
349 static int wds_cmd(struct wds *wp, u_int8_t * p, int l);
350 static void wds_wait(struct wds *wp, int reg, int mask, int val);
352 static struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys);
354 static u_int32_t frag_alloc(struct wds *wp, int size, u_int8_t **res,
356 static void frag_free(struct wds *wp, u_int32_t mask);
358 void wds_print(void);
360 #if WDS_ENABLE_SMALLOG==1
361 static __inline void smallog(char c);
362 void wds_printsmallog(void);
365 /* SCSI ID of the adapter itself */
371 #define LOGLINESIZ 81
372 #define NLOGLINES 300
373 #define DBX wds_nextlog(), LOGLINESIZ,
376 static char wds_log[NLOGLINES][LOGLINESIZ];
377 static int logwrite = 0, logread = 0;
378 static char *wds_nextlog(void);
379 void wds_printlog(void);
386 #define DBG if(0) printf
389 /* the table of supported bus methods */
390 static device_method_t wds_isa_methods[] = {
391 DEVMETHOD(device_probe, wds_probe),
392 DEVMETHOD(device_attach, wds_attach),
396 static driver_t wds_isa_driver = {
402 static devclass_t wds_devclass;
404 DRIVER_MODULE(wds, isa, wds_isa_driver, wds_devclass, 0, 0);
405 MODULE_DEPEND(wds, isa, 1, 1, 1);
406 MODULE_DEPEND(wds, cam, 1, 1, 1);
408 #if WDS_ENABLE_SMALLOG==1
409 #define SMALLOGSIZ 512
410 static char wds_smallog[SMALLOGSIZ];
411 static char *wds_smallogp = wds_smallog;
412 static char wds_smallogover = 0;
418 if (++wds_smallogp == &wds_smallog[SMALLOGSIZ]) {
419 wds_smallogp = wds_smallog;
424 #define smallog2(a, b) (smallog(a), smallog(b))
425 #define smallog3(a, b, c) (smallog(a), smallog(b), smallog(c))
426 #define smallog4(a, b, c, d) (smallog(a),smallog(b),smallog(c),smallog(d))
429 wds_printsmallog(void)
435 p = wds_smallogover ? wds_smallogp : wds_smallog;
439 if (++p == &wds_smallog[SMALLOGSIZ])
445 } while (p != wds_smallogp);
450 #define smallog2(a, b)
451 #define smallog3(a, b, c)
452 #define smallog4(a, b, c, d)
456 wds_probe(device_t dev)
464 if (isa_get_vendorid(dev))
467 wp = (struct wds *) device_get_softc(dev);
468 wp->unit = device_get_unit(dev);
471 addr = bus_get_resource_start(dev, SYS_RES_IOPORT, 0 /*rid*/);
472 if (addr == 0 || addr <0x300 || addr > 0x3f8 || addr & 0x7) {
473 device_printf(dev, "invalid port address 0x%lx\n", addr);
477 if (bus_set_resource(dev, SYS_RES_IOPORT, 0, addr, WDS_NPORTS) < 0)
481 wp->drq = bus_get_resource_start(dev, SYS_RES_DRQ, 0 /*rid*/);
482 if (wp->drq < 5 || wp->drq > 7) {
483 device_printf(dev, "invalid DRQ %d\n", wp->drq);
488 irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0 /*rid*/);
490 device_printf(dev, "invalid IRQ %d\n", irq);
495 wp->port_r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wp->port_rid,
497 if (wp->port_r == NULL)
500 error = wds_preinit(wp);
503 * We cannot hold resources between probe and
504 * attach as we may never be attached.
506 wds_free_resources(wp);
512 wds_attach(device_t dev)
515 struct cam_devq *devq;
517 struct cam_path *pathp;
521 wp = (struct wds *)device_get_softc(dev);
522 mtx_init(&wp->lock, "wds", NULL, MTX_DEF);
525 wp->port_r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wp->port_rid,
527 if (wp->port_r == NULL)
530 /* We must now release resources on error. */
533 wp->drq_r = bus_alloc_resource_any(dev, SYS_RES_DRQ, &wp->drq_rid,
535 if (wp->drq_r == NULL)
539 wp->intr_r = bus_alloc_resource_any(dev, SYS_RES_IRQ, &wp->intr_rid,
541 if (wp->intr_r == NULL)
543 error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY |
544 INTR_MPSAFE, NULL, wds_intr, wp, &wp->intr_cookie);
548 /* now create the memory buffer */
549 error = bus_dma_tag_create(bus_get_dma_tag(dev), /*alignment*/4,
551 /*lowaddr*/BUS_SPACE_MAXADDR_24BIT,
552 /*highaddr*/ BUS_SPACE_MAXADDR,
553 /*filter*/ NULL, /*filterarg*/ NULL,
554 /*maxsize*/ sizeof(* wp->dx),
556 /*maxsegsz*/ sizeof(* wp->dx), /*flags*/ 0,
563 error = bus_dmamem_alloc(wp->bustag, (void **)&wp->dx,
564 /*flags*/ 0, &wp->busmap);
568 bus_dmamap_load(wp->bustag, wp->busmap, (void *)wp->dx,
569 sizeof(* wp->dx), wds_alloc_callback,
570 (void *)&wp->dx_p, /*flags*/0);
572 /* initialize the wds_req structures on this unit */
573 for(i=0; i<MAXSIMUL; i++) {
574 wp->dx->req[i].id = i;
575 wp->wdsr_free |= 1<<i;
578 /* initialize the memory buffer allocation for this unit */
579 if (BUFSIZ / FRAGSIZ > 32) {
580 fragsiz = (BUFSIZ / 32) & ~0x01; /* keep it word-aligned */
581 device_printf(dev, "data buffer fragment size too small. "
582 "BUFSIZE / FRAGSIZE must be <= 32\n");
584 fragsiz = FRAGSIZ & ~0x01; /* keep it word-aligned */
588 for (i = fragsiz; i <= BUFSIZ; i += fragsiz) {
590 wp->data_free = (wp->data_free << 1) | 1;
593 /* complete the hardware initialization */
594 if (wds_init(wp) != 0)
597 if (wds_getvers(wp) == -1)
598 device_printf(dev, "getvers failed\n");
599 device_printf(dev, "using %d bytes / %d frags for dma buffer\n",
602 devq = cam_simq_alloc(MAXSIMUL);
606 sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp,
607 wp->unit, &wp->lock, 1, 1, devq);
615 if (xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) {
616 cam_sim_free(sim, /* free_devq */ TRUE);
617 mtx_unlock(&wp->lock);
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 mtx_unlock(&wp->lock);
628 mtx_unlock(&wp->lock);
634 wds_free_resources(wp);
635 mtx_destroy(&wp->lock);
638 else /* exact error is unknown */
642 /* callback to save the physical address */
644 wds_alloc_callback(void *arg, bus_dma_segment_t *seg, int nseg, int error)
646 *(bus_addr_t *)arg = seg[0].ds_addr;
650 wds_free_resources(struct wds *wp)
652 /* check every resource and free if not zero */
654 /* interrupt handler */
656 bus_teardown_intr(wp->dev, wp->intr_r, wp->intr_cookie);
657 bus_release_resource(wp->dev, SYS_RES_IRQ, wp->intr_rid,
662 /* all kinds of memory maps we could have allocated */
664 bus_dmamap_unload(wp->bustag, wp->busmap);
667 if (wp->dx) { /* wp->busmap may be legitimately equal to 0 */
668 /* the map will also be freed */
669 bus_dmamem_free(wp->bustag, wp->dx, wp->busmap);
673 bus_dma_tag_destroy(wp->bustag);
676 /* release all the bus resources */
678 bus_release_resource(wp->dev, SYS_RES_DRQ,
679 wp->drq_rid, wp->drq_r);
683 bus_release_resource(wp->dev, SYS_RES_IOPORT,
684 wp->port_rid, wp->port_r);
689 /* allocate contiguous fragments from the buffer */
691 frag_alloc(struct wds *wp, int size, u_int8_t **res, u_int32_t *maskp)
697 if (size > fragsiz * nfrags)
698 return (CAM_REQ_TOO_BIG);
700 mask = 1; /* always allocate at least 1 fragment */
701 for (i = fragsiz; i < size; i += fragsiz)
702 mask = (mask << 1) | 1;
704 free = wp->data_free;
706 i = ffs(free)-1; /* ffs counts bits from 1 */
707 for (mask <<= i; i < nfrags; i++) {
708 if ((free & mask) == mask) {
709 wp->data_free &= ~mask; /* mark frags as busy */
711 *res = &wp->dx->data[fragsiz * i];
712 DBG(DBX "wds%d: allocated buffer mask=0x%x\n",
714 return (CAM_REQ_CMP);
716 if (mask & 0x80000000)
722 return (CAM_REQUEUE_REQ); /* no free memory now, try later */
726 frag_free(struct wds *wp, u_int32_t mask)
728 wp->data_free |= mask; /* mark frags as free */
729 DBG(DBX "wds%d: freed buffer mask=0x%x\n", wp->unit, mask);
732 static struct wds_req *
733 wdsr_alloc(struct wds *wp)
742 /* anyway most of the time only 1 or 2 commands will
743 * be active because SCSI disconnect is not supported
744 * by hardware, so the search should be fast enough
746 i = ffs(wp->wdsr_free) - 1;
751 wp->wdsr_free &= ~ (1<<i);
753 r->flags = 0; /* reset all flags */
754 r->ombn = i; /* luckily we have one omb per wdsr */
755 wp->dx->ombs[i].stat = 1;
759 smallog3('r', i + '0', r->ombn + '0');
771 mtx_unlock(&wp->lock);
775 wds_intr_locked(struct wds *wp)
782 DBG(DBX "wds%d: interrupt [\n", wp->unit);
785 if (bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) {
786 c = bus_read_1(wp->port_r, WDS_IRQSTAT);
787 if ((c & WDSI_MASK) == WDSI_MSVC) {
789 in = &wp->dx->imbs[c];
791 rp = cmdtovirt(wp, scsi_3btoul(in->addr));
795 wds_done(wp, rp, stat);
797 device_printf(wp->dev,
798 "got weird command address %p"
799 "from controller\n", rp);
803 device_printf(wp->dev,
804 "weird interrupt, irqstat=0x%x\n", c);
805 bus_write_1(wp->port_r, WDS_IRQACK, 0);
810 DBG(DBX "wds%d: ]\n", wp->unit);
814 wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat)
816 struct ccb_hdr *ccb_h;
817 struct ccb_scsiio *csio;
822 if (r->flags & WR_DONE) {
823 device_printf(wp->dev,
824 "request %d reported done twice\n", r->id);
825 smallog2('x', r->id + '0');
829 smallog(r->id + '0');
830 ccb_h = &r->ccb->ccb_h;
831 csio = &r->ccb->csio;
832 status = CAM_REQ_CMP_ERR;
834 DBG(DBX "wds%d: %s stat=0x%x c->stat=0x%x c->venderr=0x%x\n", wp->unit,
835 r->flags & WR_SENSE ? "(sense)" : "",
836 stat, r->cmd.stat, r->cmd.venderr);
838 if (r->flags & WR_SENSE) {
839 if (stat == ICMB_OK || (stat == ICMB_OKERR && r->cmd.stat == 0)) {
840 DBG(DBX "wds%d: sense 0x%x\n", wp->unit, r->buf[0]);
841 /* it has the same size now but for future */
842 bcopy(r->buf, &csio->sense_data,
843 sizeof(struct scsi_sense_data) > csio->sense_len ?
844 csio->sense_len : sizeof(struct scsi_sense_data));
845 if (sizeof(struct scsi_sense_data) >= csio->sense_len)
846 csio->sense_resid = 0;
850 - sizeof(struct scsi_sense_data);
851 status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR;
853 status = CAM_AUTOSENSE_FAIL;
860 csio->scsi_status = r->cmd.stat;
861 status = CAM_REQ_CMP;
866 csio->scsi_status = r->cmd.stat;
868 if (ccb_h->flags & CAM_DIS_AUTOSENSE)
869 status = CAM_SCSI_STATUS_ERROR;
871 if ( wds_runsense(wp, r) == CAM_REQ_CMP )
873 /* in case of error continue with freeing of CCB */
877 status = CAM_REQ_CMP;
883 status = CAM_SEL_TIMEOUT;
893 status = CAM_REQ_CMP_ERR;
897 if (ccb_h && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN) {
898 /* we accept only virtual addresses in wds_action() */
899 bcopy(r->buf, csio->data_ptr, csio->dxfer_len);
904 wp->dx->ombs[r->ombn].stat = 0;
907 wdsr_ccb_done(wp, r, r->ccb, status);
908 smallog3('-', ccb_h->target_id + '0', ccb_h->target_lun + '0');
910 frag_free(wp, r->mask);
913 xpt_release_simq(wp->sim, /* run queue */ 1);
915 wp->wdsr_free |= (1 << r->id);
918 DBG(DBX "wds%d: request %p done\n", wp->unit, r);
921 /* command returned bad status, request sense */
924 wds_runsense(struct wds *wp, struct wds_req *r)
927 struct ccb_hdr *ccb_h;
929 ccb_h = &r->ccb->ccb_h;
931 r->flags |= WR_SENSE;
932 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd),
933 wp->dx->ombs[r->ombn].addr);
934 bzero(&r->cmd, sizeof r->cmd);
935 r->cmd.cmd = WDSX_SCSICMD;
936 r->cmd.targ = (ccb_h->target_id << 5) |
939 scsi_ulto3b(0, r->cmd.next);
941 r->cmd.scb[0] = REQUEST_SENSE;
942 r->cmd.scb[1] = ccb_h->target_lun << 5;
943 r->cmd.scb[4] = sizeof(struct scsi_sense_data);
945 scsi_ulto3b(WDSTOPHYS(wp, r->buf), r->cmd.data);
946 scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len);
949 bus_write_1(wp->port_r, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
951 wp->dx->ombs[r->ombn].stat = 1;
952 c = WDSC_MSTART(r->ombn);
954 if (wds_cmd(wp, &c, sizeof c) != 0) {
955 device_printf(wp->dev, "unable to start outgoing sense mbox\n");
956 wp->dx->ombs[r->ombn].stat = 0;
957 wdsr_ccb_done(wp, r, r->ccb, CAM_AUTOSENSE_FAIL);
958 return CAM_AUTOSENSE_FAIL;
960 DBG(DBX "wds%d: enqueued status cmd 0x%x, r=%p\n",
961 wp->unit, r->cmd.scb[0] & 0xFF, r);
962 /* don't free CCB yet */
963 smallog3('*', ccb_h->target_id + '0',
964 ccb_h->target_lun + '0');
970 wds_getvers(struct wds *wp)
978 device_printf(wp->dev, "no request slot available!\n");
981 r->flags &= ~WR_DONE;
985 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr);
987 bzero(&r->cmd, sizeof r->cmd);
988 r->cmd.cmd = WDSX_GETFIRMREV;
990 bus_write_1(wp->port_r, WDS_HCR, WDSH_DRQEN);
992 c = WDSC_MSTART(r->ombn);
993 if (wds_cmd(wp, (u_int8_t *) & c, sizeof c)) {
994 device_printf(wp->dev, "version request failed\n");
995 wp->wdsr_free |= (1 << r->id);
996 wp->dx->ombs[r->ombn].stat = 0;
1001 while ((bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) == 0) {
1004 device_printf(wp->dev, "getvers timeout\n");
1008 wds_intr_locked(wp);
1009 if (r->flags & WR_DONE) {
1010 device_printf(wp->dev, "firmware version %d.%02d\n",
1011 r->cmd.targ, r->cmd.scb[0]);
1012 wp->wdsr_free |= (1 << r->id);
1019 wdsr_ccb_done(struct wds *wp, struct wds_req *r,
1020 union ccb *ccb, u_int32_t status)
1022 ccb->ccb_h.ccb_wdsr = 0;
1025 /* To implement timeouts we would need to know how to abort the
1026 * command on controller, and this is a great mystery.
1027 * So for now we just pass the responsibility for timeouts
1028 * to the controller itself, it does that reasonably good.
1030 /* we're about to free a hcb, so the shortage has ended */
1031 frag_free(wp, r->mask);
1032 if (wp->want_wdsr && status != CAM_REQUEUE_REQ) {
1034 status |= CAM_RELEASE_SIMQ;
1037 wp->wdsr_free |= (1 << r->id);
1040 status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED));
1045 wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio)
1047 int unit = cam_sim_unit(sim);
1049 struct ccb_hdr *ccb_h;
1055 wp = (struct wds *)cam_sim_softc(sim);
1056 ccb_h = &csio->ccb_h;
1058 DBG(DBX "wds%d: cmd TARG=%d LUN=%jx\n", unit, ccb_h->target_id,
1059 (uintmax_t)ccb_h->target_lun);
1061 if (ccb_h->target_id > 7 || ccb_h->target_id == WDS_HBA_ID) {
1062 ccb_h->status = CAM_TID_INVALID;
1063 xpt_done((union ccb *) csio);
1066 if (ccb_h->target_lun > 7) {
1067 ccb_h->status = CAM_LUN_INVALID;
1068 xpt_done((union ccb *) csio);
1071 if (csio->dxfer_len > BUFSIZ) {
1072 ccb_h->status = CAM_REQ_TOO_BIG;
1073 xpt_done((union ccb *) csio);
1076 if ((ccb_h->flags & CAM_DATA_MASK) != CAM_DATA_VADDR) {
1077 /* don't support these */
1078 ccb_h->status = CAM_REQ_INVALID;
1079 xpt_done((union ccb *) csio);
1084 * this check is mostly for debugging purposes,
1085 * "can't happen" normally.
1088 DBG(DBX "wds%d: someone already waits for buffer\n", unit);
1090 n = xpt_freeze_simq(sim, /* count */ 1);
1092 ccb_h->status = CAM_REQUEUE_REQ;
1093 xpt_done((union ccb *) csio);
1099 device_printf(wp->dev, "no request slot available!\n");
1101 n = xpt_freeze_simq(sim, /* count */ 1);
1102 smallog2('f', '0'+n);
1103 ccb_h->status = CAM_REQUEUE_REQ;
1104 xpt_done((union ccb *) csio);
1108 ccb_h->ccb_wdsr = (void *) r;
1109 r->ccb = (union ccb *) csio;
1111 switch (error = frag_alloc(wp, csio->dxfer_len, &r->buf, &r->mask)) {
1114 case CAM_REQUEUE_REQ:
1115 DBG(DBX "wds%d: no data buffer available\n", unit);
1117 n = xpt_freeze_simq(sim, /* count */ 1);
1118 smallog2('f', '0'+n);
1119 wdsr_ccb_done(wp, r, r->ccb, CAM_REQUEUE_REQ);
1122 DBG(DBX "wds%d: request is too big\n", unit);
1123 wdsr_ccb_done(wp, r, r->ccb, error);
1127 ccb_h->status |= CAM_SIM_QUEUED;
1128 r->flags &= ~WR_DONE;
1130 scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr);
1132 bzero(&r->cmd, sizeof r->cmd);
1133 r->cmd.cmd = WDSX_SCSICMD;
1134 r->cmd.targ = (ccb_h->target_id << 5) | ccb_h->target_lun;
1136 if (ccb_h->flags & CAM_CDB_POINTER)
1137 bcopy(csio->cdb_io.cdb_ptr, &r->cmd.scb,
1138 csio->cdb_len < 12 ? csio->cdb_len : 12);
1140 bcopy(csio->cdb_io.cdb_bytes, &r->cmd.scb,
1141 csio->cdb_len < 12 ? csio->cdb_len : 12);
1143 scsi_ulto3b(csio->dxfer_len, r->cmd.len);
1145 if (csio->dxfer_len > 0
1146 && (ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_OUT) {
1147 /* we already rejected physical or scattered addresses */
1148 bcopy(csio->data_ptr, r->buf, csio->dxfer_len);
1150 scsi_ulto3b(csio->dxfer_len ? WDSTOPHYS(wp, r->buf) : 0, r->cmd.data);
1152 if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
1153 r->cmd.write = 0x80;
1155 r->cmd.write = 0x00;
1157 scsi_ulto3b(0, r->cmd.next);
1159 bus_write_1(wp->port_r, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
1161 c = WDSC_MSTART(r->ombn);
1163 if (wds_cmd(wp, &c, sizeof c) != 0) {
1164 device_printf(wp->dev, "unable to start outgoing mbox\n");
1165 wp->dx->ombs[r->ombn].stat = 0;
1166 wdsr_ccb_done(wp, r, r->ccb, CAM_RESRC_UNAVAIL);
1169 DBG(DBX "wds%d: enqueued cmd 0x%x, r=%p\n", unit,
1170 r->cmd.scb[0] & 0xFF, r);
1172 smallog3('+', ccb_h->target_id + '0', ccb_h->target_lun + '0');
1176 wds_action(struct cam_sim * sim, union ccb * ccb)
1178 int unit = cam_sim_unit(sim);
1180 DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code);
1181 switch (ccb->ccb_h.func_code) {
1183 DBG(DBX "wds%d: SCSI IO entered\n", unit);
1184 wds_scsi_io(sim, &ccb->csio);
1185 DBG(DBX "wds%d: SCSI IO returned\n", unit);
1188 /* how to do it right ? */
1189 printf("wds%d: reset\n", unit);
1190 ccb->ccb_h.status = CAM_REQ_CMP;
1194 ccb->ccb_h.status = CAM_UA_ABORT;
1197 case XPT_CALC_GEOMETRY:
1199 struct ccb_calc_geometry *ccg;
1201 u_int32_t secs_per_cylinder;
1204 size_mb = ccg->volume_size
1205 / ((1024L * 1024L) / ccg->block_size);
1208 ccg->secs_per_track = 16;
1209 secs_per_cylinder = ccg->heads * ccg->secs_per_track;
1210 ccg->cylinders = ccg->volume_size / secs_per_cylinder;
1211 ccb->ccb_h.status = CAM_REQ_CMP;
1215 case XPT_PATH_INQ: /* Path routing inquiry */
1217 struct ccb_pathinq *cpi = &ccb->cpi;
1219 cpi->version_num = 1; /* XXX??? */
1220 cpi->hba_inquiry = 0; /* nothing fancy */
1221 cpi->target_sprt = 0;
1223 cpi->hba_eng_cnt = 0;
1224 cpi->max_target = 7;
1226 cpi->initiator_id = WDS_HBA_ID;
1228 cpi->bus_id = cam_sim_bus(sim);
1229 cpi->base_transfer_speed = 3300;
1230 strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
1231 strncpy(cpi->hba_vid, "WD/FDC", HBA_IDLEN);
1232 strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
1233 cpi->unit_number = cam_sim_unit(sim);
1234 cpi->ccb_h.status = CAM_REQ_CMP;
1239 ccb->ccb_h.status = CAM_REQ_INVALID;
1246 wds_poll(struct cam_sim * sim)
1248 wds_intr_locked(cam_sim_softc(sim));
1251 /* part of initialization done in probe() */
1252 /* returns 0 if OK, ENXIO if bad */
1255 wds_preinit(struct wds *wp)
1260 * Sending a command causes the CMDRDY bit to clear.
1262 bus_write_1(wp->port_r, WDS_CMD, WDSC_NOOP);
1263 if (bus_read_1(wp->port_r, WDS_STAT) & WDS_RDY)
1267 * the controller exists. reset and init.
1269 bus_write_1(wp->port_r, WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET);
1271 bus_write_1(wp->port_r, WDS_HCR, 0);
1273 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
1274 for (i = 0; i < 10; i++) {
1275 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) == WDS_RDY)
1279 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY)
1287 /* part of initialization done in attach() */
1288 /* returns 0 if OK, 1 if bad */
1291 wds_init(struct wds *wp)
1293 struct wds_setup init;
1297 bus_write_1(wp->port_r, WDS_HCR, WDSH_DRQEN);
1299 isa_dmacascade(wp->drq);
1301 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY) {
1302 for (i = 0; i < 10; i++) {
1303 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) == WDS_RDY)
1307 if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY)
1311 bzero(&init, sizeof init);
1312 init.cmd = WDSC_INIT;
1313 init.scsi_id = WDS_HBA_ID;
1316 scsi_ulto3b(WDSTOPHYS(wp, &wp->dx->ombs), init.mbaddr);
1318 init.nomb = WDS_NOMB;
1319 init.nimb = WDS_NIMB;
1321 wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
1322 if (wds_cmd(wp, (u_int8_t *) & init, sizeof init) != 0) {
1323 device_printf(wp->dev, "wds_cmd init failed\n");
1326 wds_wait(wp, WDS_STAT, WDS_INIT, WDS_INIT);
1328 wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
1330 bzero(&wc, sizeof wc);
1331 wc.cmd = WDSC_DISUNSOL;
1332 if (wds_cmd(wp, (char *) &wc, sizeof wc) != 0) {
1333 device_printf(wp->dev, "wds_cmd init2 failed\n");
1340 wds_cmd(struct wds *wp, u_int8_t * p, int l)
1345 bus_write_1(wp->port_r, WDS_CMD, *p);
1346 wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
1347 } while (bus_read_1(wp->port_r, WDS_STAT) & WDS_REJ);
1351 wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
1357 wds_wait(struct wds *wp, int reg, int mask, int val)
1359 while ((bus_read_1(wp->port_r, reg) & mask) != val)
1363 static struct wds_req *
1364 cmdtovirt(struct wds *wp, u_int32_t phys)
1368 a = WDSTOVIRT(wp, (uintptr_t)phys);
1369 if( a < (char *)&wp->dx->req[0] || a>= (char *)&wp->dx->req[MAXSIMUL]) {
1370 device_printf(wp->dev, "weird phys address 0x%x\n", phys);
1373 a -= (int)offsetof(struct wds_req, cmd); /* convert cmd to request */
1374 return ((struct wds_req *)a);
1377 /* for debugging, print out all the data about the status of devices */
1386 for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) {
1387 wp = (struct wds *) devclass_get_device(wds_devclass, unit);
1390 printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n",
1391 unit, wp->want_wdsr, bus_read_1(wp->port_r, WDS_STAT) & 0xff,
1392 (bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) ? "ready" : "no",
1393 bus_read_1(wp->port_r, WDS_IRQSTAT) & 0xff);
1394 for (i = 0; i < MAXSIMUL; i++) {
1395 r = &wp->dx->req[i];
1396 if( wp->wdsr_free & (1 << r->id) ) {
1397 printf("req=%d flg=0x%x ombn=%d ombstat=%d "
1398 "mask=0x%x targ=%d lun=%d cmd=0x%x\n",
1399 i, r->flags, r->ombn,
1400 wp->dx->ombs[r->ombn].stat,
1401 r->mask, r->cmd.targ >> 5,
1402 r->cmd.targ & 7, r->cmd.scb[0]);
1409 /* create circular log buffer */
1415 if (++logwrite >= NLOGLINES)
1417 if (logread == logwrite)
1418 if (++logread >= NLOGLINES)
1420 return (wds_log[n]);
1426 /* print the circular buffer */
1429 for (i = logread; i != logwrite;) {
1430 printf("%s", wds_log[i]);
1437 #endif /* WDS_DEBUG */