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#include <sys/malloc.h>
136
137#include <sys/bio.h>
138#include <sys/buf.h>
139
140#include <cam/cam.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>
147
148
149#include <vm/vm.h>
150#include <vm/vm_param.h>
151#include <vm/pmap.h>
152
153#include <sys/module.h>
154#include <sys/bus.h>
155#include <machine/bus.h>
156#include <machine/resource.h>
157#include <sys/rman.h>
158
159#include <isa/isavar.h>
160#include <isa/pnpvar.h>
161
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) )
164
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
169
170
171/* WD7000 registers */
172#define WDS_STAT		0	/* read */
173#define WDS_IRQSTAT		1	/* read */
174
175#define WDS_CMD			0	/* write */
176#define WDS_IRQACK		1	/* write */
177#define WDS_HCR			2	/* write */
178
179#define WDS_NPORTS		4 /* number of ports used */
180
181/* WDS_STAT (read) defs */
182#define WDS_IRQ			0x80
183#define WDS_RDY			0x40
184#define WDS_REJ			0x20
185#define WDS_INIT		0x10
186
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
192
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 */
203
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
209
210struct wds_cmd {
211	u_int8_t	cmd;
212	u_int8_t	targ;
213	u_int8_t	scb[12];
214	u_int8_t	stat;
215	u_int8_t	venderr;
216	u_int8_t	len[3];
217	u_int8_t	data[3];
218	u_int8_t	next[3];
219	u_int8_t	write;
220	u_int8_t	xx[6];
221};
222
223struct wds_req {
224	struct	   wds_cmd cmd;
225	union	   ccb *ccb;
226	enum {
227		WR_DONE = 0x01,
228		WR_SENSE = 0x02
229	} flags;
230	u_int8_t  *buf;		/* address of linear data buffer */
231	u_int32_t  mask;	/* mask of allocated fragments */
232	u_int8_t	ombn;
233	u_int8_t	id;	/* number of request */
234};
235
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
252
253struct wds_mb {
254	u_int8_t	stat;
255	u_int8_t	addr[3];
256};
257/* ICMB status value */
258#define ICMB_OK			0x01
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
268
269struct wds_setup {
270	u_int8_t	cmd;
271	u_int8_t	scsi_id;
272	u_int8_t	buson_t;
273	u_int8_t	busoff_t;
274	u_int8_t	xx;
275	u_int8_t	mbaddr[3];
276	u_int8_t	nomb;
277	u_int8_t	nimb;
278};
279
280/* the code depends on equality of these parameters */
281#define MAXSIMUL	8
282#define WDS_NOMB	MAXSIMUL
283#define WDS_NIMB	MAXSIMUL
284
285static int	fragsiz;
286static int	nfrags;
287
288/* structure for data exchange with controller */
289
290struct wdsdx {
291	struct wds_req	req[MAXSIMUL];
292	struct wds_mb	ombs[MAXSIMUL];
293	struct wds_mb	imbs[MAXSIMUL];
294	u_int8_t	data[BUFSIZ];
295};
296
297/* structure softc */
298
299struct wds {
300	device_t	 dev;
301	struct mtx	 lock;
302	int		 unit;
303	int		 drq;
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 */
307	u_int32_t	 data_free;
308	u_int32_t	 wdsr_free;
309	struct wdsdx	*dx;
310	bus_addr_t	 dx_p; /* physical address */
311	struct resource	*port_r;
312	int		 port_rid;
313	struct resource	*drq_r;
314	int		 drq_rid;
315	struct resource *intr_r;
316	int		 intr_rid;
317	void		*intr_cookie;
318	bus_dma_tag_t	 bustag;
319	bus_dmamap_t	 busmap;
320};
321
322#define ccb_wdsr	spriv_ptr1	/* for wds request */
323
324static int      wds_probe(device_t dev);
325static int      wds_attach(device_t dev);
326static void     wds_intr(void *arg);
327static void     wds_intr_locked(struct wds *wp);
328
329static void     wds_action(struct cam_sim * sim, union ccb * ccb);
330static void     wds_poll(struct cam_sim * sim);
331
332static int      wds_preinit(struct wds *wp);
333static int      wds_init(struct wds *wp);
334
335static void     wds_alloc_callback(void *arg, bus_dma_segment_t *seg,
336	 int nseg, int error);
337static void     wds_free_resources(struct wds *wp);
338
339static struct wds_req *wdsr_alloc(struct wds *wp);
340
341static void     wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio);
342static void     wdsr_ccb_done(struct wds *wp, struct wds_req *r,
343			      union ccb *ccb, u_int32_t status);
344
345static void     wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat);
346static int      wds_runsense(struct wds *wp, struct wds_req *r);
347static int      wds_getvers(struct wds *wp);
348
349static int      wds_cmd(struct wds *wp, u_int8_t * p, int l);
350static void     wds_wait(struct wds *wp, int reg, int mask, int val);
351
352static struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys);
353
354static u_int32_t frag_alloc(struct wds *wp, int size, u_int8_t **res,
355			    u_int32_t *maskp);
356static void     frag_free(struct wds *wp, u_int32_t mask);
357
358void            wds_print(void);
359
360#if WDS_ENABLE_SMALLOG==1
361static __inline void   smallog(char c);
362void 	wds_printsmallog(void);
363#endif /* SMALLOG */
364
365/* SCSI ID of the adapter itself */
366#ifndef WDS_HBA_ID
367#define WDS_HBA_ID 7
368#endif
369
370#if WDS_DEBUG == 2
371#define LOGLINESIZ	81
372#define NLOGLINES	300
373#define DBX	wds_nextlog(), LOGLINESIZ,
374#define DBG	snprintf
375
376static char     wds_log[NLOGLINES][LOGLINESIZ];
377static int      logwrite = 0, logread = 0;
378static char    *wds_nextlog(void);
379void            wds_printlog(void);
380
381#elif WDS_DEBUG != 0
382#define DBX
383#define DBG	printf
384#else
385#define DBX
386#define DBG	if(0) printf
387#endif
388
389/* the table of supported bus methods */
390static device_method_t wds_isa_methods[] = {
391	DEVMETHOD(device_probe,		wds_probe),
392	DEVMETHOD(device_attach,	wds_attach),
393	{ 0, 0 }
394};
395
396static driver_t wds_isa_driver = {
397	"wds",
398	wds_isa_methods,
399	sizeof(struct wds),
400};
401
402static devclass_t wds_devclass;
403
404DRIVER_MODULE(wds, isa, wds_isa_driver, wds_devclass, 0, 0);
405MODULE_DEPEND(wds, isa, 1, 1, 1);
406MODULE_DEPEND(wds, cam, 1, 1, 1);
407
408#if WDS_ENABLE_SMALLOG==1
409#define SMALLOGSIZ	512
410static char	 wds_smallog[SMALLOGSIZ];
411static char	*wds_smallogp = wds_smallog;
412static char	 wds_smallogover = 0;
413
414static __inline void
415smallog(char c)
416{
417	*wds_smallogp = c;
418	if (++wds_smallogp == &wds_smallog[SMALLOGSIZ]) {
419		wds_smallogp = wds_smallog;
420		wds_smallogover = 1;
421	}
422}
423
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))
427
428void
429wds_printsmallog(void)
430{
431	int	 i;
432	char	*p;
433
434	printf("wds: ");
435	p = wds_smallogover ? wds_smallogp : wds_smallog;
436	i = 0;
437	do {
438		printf("%c", *p);
439		if (++p == &wds_smallog[SMALLOGSIZ])
440			p = wds_smallog;
441		if (++i == 70) {
442			i = 0;
443			printf("\nwds: ");
444		}
445	} while (p != wds_smallogp);
446	printf("\n");
447}
448#else
449#define smallog(a)
450#define smallog2(a, b)
451#define smallog3(a, b, c)
452#define smallog4(a, b, c, d)
453#endif				/* SMALLOG */
454
455static int
456wds_probe(device_t dev)
457{
458	struct	wds *wp;
459	unsigned long addr;
460	int	error = 0;
461	int	irq;
462
463	/* No pnp support */
464	if (isa_get_vendorid(dev))
465		return (ENXIO);
466
467	wp = (struct wds *) device_get_softc(dev);
468	wp->unit = device_get_unit(dev);
469	wp->dev = dev;
470
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);
474		return (ENXIO);
475	}
476
477	if (bus_set_resource(dev, SYS_RES_IOPORT, 0, addr, WDS_NPORTS) < 0)
478		return (ENXIO);
479
480	/* get the DRQ */
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);
484		return (ENXIO);
485	}
486
487	/* get the IRQ */
488	irq = bus_get_resource_start(dev, SYS_RES_IRQ, 0 /*rid*/);
489	if (irq < 3) {
490		device_printf(dev, "invalid IRQ %d\n", irq);
491		return (ENXIO);
492	}
493
494	wp->port_rid = 0;
495	wp->port_r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wp->port_rid,
496	    RF_ACTIVE);
497	if (wp->port_r == NULL)
498		return (ENXIO);
499
500	error = wds_preinit(wp);
501
502	/*
503	 * We cannot hold resources between probe and
504	 * attach as we may never be attached.
505	 */
506	wds_free_resources(wp);
507
508	return (error);
509}
510
511static int
512wds_attach(device_t dev)
513{
514	struct	wds *wp;
515	struct	cam_devq *devq;
516	struct	cam_sim *sim;
517	struct	cam_path *pathp;
518	int	i;
519	int	error = 0;
520
521	wp = (struct wds *)device_get_softc(dev);
522	mtx_init(&wp->lock, "wds", NULL, MTX_DEF);
523
524	wp->port_rid = 0;
525	wp->port_r = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &wp->port_rid,
526	    RF_ACTIVE);
527	if (wp->port_r == NULL)
528		goto bad;
529
530	/* We must now release resources on error. */
531
532	wp->drq_rid = 0;
533	wp->drq_r = bus_alloc_resource_any(dev, SYS_RES_DRQ, &wp->drq_rid,
534	    RF_ACTIVE);
535	if (wp->drq_r == NULL)
536		goto bad;
537
538	wp->intr_rid = 0;
539	wp->intr_r = bus_alloc_resource_any(dev, SYS_RES_IRQ, &wp->intr_rid,
540	    RF_ACTIVE);
541	if (wp->intr_r == NULL)
542		goto bad;
543	error = bus_setup_intr(dev, wp->intr_r, INTR_TYPE_CAM | INTR_ENTROPY |
544	    INTR_MPSAFE, NULL, wds_intr, wp, &wp->intr_cookie);
545	if (error)
546		goto bad;
547
548	/* now create the memory buffer */
549	error = bus_dma_tag_create(bus_get_dma_tag(dev), /*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				   /*lockfunc*/NULL,
558				   /*lockarg*/NULL,
559				   &wp->bustag);
560	if (error)
561		goto bad;
562
563	error = bus_dmamem_alloc(wp->bustag, (void **)&wp->dx,
564				 /*flags*/ 0, &wp->busmap);
565	if (error)
566		goto bad;
567
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);
571
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;
576	}
577
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");
583	} else
584		fragsiz = FRAGSIZ & ~0x01; /* keep it word-aligned */
585
586	wp->data_free = 0;
587	nfrags = 0;
588	for (i = fragsiz; i <= BUFSIZ; i += fragsiz) {
589		nfrags++;
590		wp->data_free = (wp->data_free << 1) | 1;
591	}
592
593	/* complete the hardware initialization */
594	if (wds_init(wp) != 0)
595		goto bad;
596
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",
600		      BUFSIZ, nfrags);
601
602	devq = cam_simq_alloc(MAXSIMUL);
603	if (devq == NULL)
604		goto bad;
605
606	sim = cam_sim_alloc(wds_action, wds_poll, "wds", (void *) wp,
607			    wp->unit, &wp->lock, 1, 1, devq);
608	if (sim == NULL) {
609		cam_simq_free(devq);
610		goto bad;
611	}
612	wp->sim = sim;
613
614	mtx_lock(&wp->lock);
615	if (xpt_bus_register(sim, dev, 0) != CAM_SUCCESS) {
616		cam_sim_free(sim, /* free_devq */ TRUE);
617		mtx_unlock(&wp->lock);
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		mtx_unlock(&wp->lock);
626		goto bad;
627	}
628	mtx_unlock(&wp->lock);
629	wp->path = pathp;
630
631	return (0);
632
633bad:
634	wds_free_resources(wp);
635	mtx_destroy(&wp->lock);
636	if (error)
637		return (error);
638	else /* exact error is unknown */
639		return (ENXIO);
640}
641
642/* callback to save the physical address */
643static void
644wds_alloc_callback(void *arg, bus_dma_segment_t *seg,  int nseg, int error)
645{
646	*(bus_addr_t *)arg = seg[0].ds_addr;
647}
648
649static void
650wds_free_resources(struct wds *wp)
651{
652	/* check every resource and free if not zero */
653
654	/* interrupt handler */
655	if (wp->intr_r) {
656		bus_teardown_intr(wp->dev, wp->intr_r, wp->intr_cookie);
657		bus_release_resource(wp->dev, SYS_RES_IRQ, wp->intr_rid,
658				     wp->intr_r);
659		wp->intr_r = 0;
660	}
661
662	/* all kinds of memory maps we could have allocated */
663	if (wp->dx_p) {
664		bus_dmamap_unload(wp->bustag, wp->busmap);
665		wp->dx_p = 0;
666	}
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);
670		wp->dx = 0;
671	}
672	if (wp->bustag) {
673		bus_dma_tag_destroy(wp->bustag);
674		wp->bustag = 0;
675	}
676	/* release all the bus resources */
677	if (wp->drq_r) {
678		bus_release_resource(wp->dev, SYS_RES_DRQ,
679				     wp->drq_rid, wp->drq_r);
680		wp->drq_r = 0;
681	}
682	if (wp->port_r) {
683		bus_release_resource(wp->dev, SYS_RES_IOPORT,
684				     wp->port_rid, wp->port_r);
685		wp->port_r = 0;
686	}
687}
688
689/* allocate contiguous fragments from the buffer */
690static u_int32_t
691frag_alloc(struct wds *wp, int size, u_int8_t **res, u_int32_t *maskp)
692{
693	int	i;
694	u_int32_t	mask;
695	u_int32_t	free;
696
697	if (size > fragsiz * nfrags)
698		return (CAM_REQ_TOO_BIG);
699
700	mask = 1;		/* always allocate at least 1 fragment */
701	for (i = fragsiz; i < size; i += fragsiz)
702		mask = (mask << 1) | 1;
703
704	free = wp->data_free;
705	if(free != 0) {
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 */
710				*maskp = mask;
711				*res = &wp->dx->data[fragsiz * i];
712				DBG(DBX "wds%d: allocated buffer mask=0x%x\n",
713					wp->unit, mask);
714				return (CAM_REQ_CMP);
715			}
716			if (mask & 0x80000000)
717				break;
718
719			mask <<= 1;
720		}
721	}
722	return (CAM_REQUEUE_REQ);	/* no free memory now, try later */
723}
724
725static void
726frag_free(struct wds *wp, u_int32_t mask)
727{
728	wp->data_free |= mask;	/* mark frags as free */
729	DBG(DBX "wds%d: freed buffer mask=0x%x\n", wp->unit, mask);
730}
731
732static struct wds_req *
733wdsr_alloc(struct wds *wp)
734{
735	struct	wds_req *r;
736	int	x;
737	int	i;
738
739	r = NULL;
740	x = splcam();
741
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
745	 */
746	i = ffs(wp->wdsr_free) - 1;
747	if(i < 0) {
748		splx(x);
749		return (NULL);
750	}
751	wp->wdsr_free &= ~ (1<<i);
752	r = &wp->dx->req[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;
756
757	r->mask = 0;
758	splx(x);
759	smallog3('r', i + '0', r->ombn + '0');
760	return (r);
761}
762
763static void
764wds_intr(void *arg)
765{
766	struct wds *wp;
767
768	wp = arg;
769	mtx_lock(&wp->lock);
770	wds_intr_locked(wp);
771	mtx_unlock(&wp->lock);
772}
773
774static void
775wds_intr_locked(struct wds *wp)
776{
777	struct	 wds_req *rp;
778	struct	 wds_mb *in;
779	u_int8_t stat;
780	u_int8_t c;
781
782	DBG(DBX "wds%d: interrupt [\n", wp->unit);
783	smallog('[');
784
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) {
788			c = c & ~WDSI_MASK;
789			in = &wp->dx->imbs[c];
790
791			rp = cmdtovirt(wp, scsi_3btoul(in->addr));
792			stat = in->stat;
793
794			if (rp != NULL)
795				wds_done(wp, rp, stat);
796			else
797				device_printf(wp->dev,
798					      "got weird command address %p"
799					      "from controller\n", rp);
800
801			in->stat = 0;
802		} else
803			device_printf(wp->dev,
804				      "weird interrupt, irqstat=0x%x\n", c);
805		bus_write_1(wp->port_r, WDS_IRQACK, 0);
806	} else {
807		smallog('?');
808	}
809	smallog(']');
810	DBG(DBX "wds%d: ]\n", wp->unit);
811}
812
813static void
814wds_done(struct wds *wp, struct wds_req *r, u_int8_t stat)
815{
816	struct	ccb_hdr *ccb_h;
817	struct	ccb_scsiio *csio;
818	int	status;
819
820	smallog('d');
821
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');
826		return;
827	}
828
829	smallog(r->id + '0');
830	ccb_h = &r->ccb->ccb_h;
831	csio = &r->ccb->csio;
832	status = CAM_REQ_CMP_ERR;
833
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);
837
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;
847			else
848				csio->sense_resid =
849					csio->sense_len
850				      - sizeof(struct scsi_sense_data);
851			status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR;
852		} else {
853			status = CAM_AUTOSENSE_FAIL;
854		}
855	} else {
856		switch (stat) {
857		case ICMB_OK:
858			if (ccb_h) {
859				csio->resid = 0;
860				csio->scsi_status = r->cmd.stat;
861				status = CAM_REQ_CMP;
862			}
863			break;
864		case ICMB_OKERR:
865			if (ccb_h) {
866				csio->scsi_status = r->cmd.stat;
867				if (r->cmd.stat) {
868					if (ccb_h->flags & CAM_DIS_AUTOSENSE)
869						status = CAM_SCSI_STATUS_ERROR;
870					else {
871						if ( wds_runsense(wp, r) == CAM_REQ_CMP )
872							return;
873						/* in case of error continue with freeing of CCB */
874					}
875				} else {
876					csio->resid = 0;
877					status = CAM_REQ_CMP;
878				}
879			}
880			break;
881		case ICMB_ETIME:
882			if (ccb_h)
883				status = CAM_SEL_TIMEOUT;
884			break;
885		case ICMB_ERESET:
886		case ICMB_ETARCMD:
887		case ICMB_ERESEL:
888		case ICMB_ESEL:
889		case ICMB_EABORT:
890		case ICMB_ESRESET:
891		case ICMB_EHRESET:
892			if (ccb_h)
893				status = CAM_REQ_CMP_ERR;
894			break;
895		}
896
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);
900		}
901	}
902
903	r->flags |= WR_DONE;
904	wp->dx->ombs[r->ombn].stat = 0;
905
906	if (ccb_h) {
907		wdsr_ccb_done(wp, r, r->ccb, status);
908		smallog3('-', ccb_h->target_id + '0', ccb_h->target_lun + '0');
909	} else {
910		frag_free(wp, r->mask);
911		if (wp->want_wdsr) {
912			wp->want_wdsr = 0;
913			xpt_release_simq(wp->sim, /* run queue */ 1);
914		}
915		wp->wdsr_free |= (1 << r->id);
916	}
917
918	DBG(DBX "wds%d: request %p done\n", wp->unit, r);
919}
920
921/* command returned bad status, request sense */
922
923static int
924wds_runsense(struct wds *wp, struct wds_req *r)
925{
926	u_int8_t          c;
927	struct	ccb_hdr *ccb_h;
928
929	ccb_h = &r->ccb->ccb_h;
930
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) |
937		ccb_h->target_lun;
938
939	scsi_ulto3b(0, r->cmd.next);
940
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);
944	r->cmd.scb[5] = 0;
945	scsi_ulto3b(WDSTOPHYS(wp, r->buf), r->cmd.data);
946	scsi_ulto3b(sizeof(struct scsi_sense_data), r->cmd.len);
947	r->cmd.write = 0x80;
948
949	bus_write_1(wp->port_r, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
950
951	wp->dx->ombs[r->ombn].stat = 1;
952	c = WDSC_MSTART(r->ombn);
953
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;
959	} else {
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');
965		return CAM_REQ_CMP;
966	}
967}
968
969static int
970wds_getvers(struct wds *wp)
971{
972	struct	 wds_req *r;
973	u_int8_t c;
974	int	 i;
975
976	r = wdsr_alloc(wp);
977	if (!r) {
978		device_printf(wp->dev, "no request slot available!\n");
979		return (-1);
980	}
981	r->flags &= ~WR_DONE;
982
983	r->ccb = NULL;
984
985	scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr);
986
987	bzero(&r->cmd, sizeof r->cmd);
988	r->cmd.cmd = WDSX_GETFIRMREV;
989
990	bus_write_1(wp->port_r, WDS_HCR, WDSH_DRQEN);
991
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;
997		return (-1);
998	}
999	while (1) {
1000		i = 0;
1001		while ((bus_read_1(wp->port_r, WDS_STAT) & WDS_IRQ) == 0) {
1002			DELAY(9000);
1003			if (++i == 100) {
1004				device_printf(wp->dev, "getvers timeout\n");
1005				return (-1);
1006			}
1007		}
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);
1013			return (0);
1014		}
1015	}
1016}
1017
1018static void
1019wdsr_ccb_done(struct wds *wp, struct wds_req *r,
1020	      union ccb *ccb, u_int32_t status)
1021{
1022	ccb->ccb_h.ccb_wdsr = 0;
1023
1024	if (r != NULL) {
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.
1029		 */
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) {
1033			wp->want_wdsr = 0;
1034			status |= CAM_RELEASE_SIMQ;
1035			smallog('R');
1036		}
1037		wp->wdsr_free |= (1 << r->id);
1038	}
1039	ccb->ccb_h.status =
1040	    status | (ccb->ccb_h.status & ~(CAM_STATUS_MASK | CAM_SIM_QUEUED));
1041	xpt_done(ccb);
1042}
1043
1044static void
1045wds_scsi_io(struct cam_sim * sim, struct ccb_scsiio * csio)
1046{
1047	int	 unit = cam_sim_unit(sim);
1048	struct	 wds *wp;
1049	struct	 ccb_hdr *ccb_h;
1050	struct	 wds_req *r;
1051	u_int8_t c;
1052	int	 error;
1053	int	 n;
1054
1055	wp = (struct wds *)cam_sim_softc(sim);
1056	ccb_h = &csio->ccb_h;
1057
1058	DBG(DBX "wds%d: cmd TARG=%d LUN=%jx\n", unit, ccb_h->target_id,
1059	    (uintmax_t)ccb_h->target_lun);
1060
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);
1064		return;
1065	}
1066	if (ccb_h->target_lun > 7) {
1067		ccb_h->status = CAM_LUN_INVALID;
1068		xpt_done((union ccb *) csio);
1069		return;
1070	}
1071	if (csio->dxfer_len > BUFSIZ) {
1072		ccb_h->status = CAM_REQ_TOO_BIG;
1073		xpt_done((union ccb *) csio);
1074		return;
1075	}
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);
1080		return;
1081	}
1082
1083	/*
1084	 * this check is mostly for debugging purposes,
1085	 * "can't happen" normally.
1086	 */
1087	if(wp->want_wdsr) {
1088		DBG(DBX "wds%d: someone already waits for buffer\n", unit);
1089		smallog('b');
1090		n = xpt_freeze_simq(sim, /* count */ 1);
1091		smallog('0'+n);
1092		ccb_h->status = CAM_REQUEUE_REQ;
1093		xpt_done((union ccb *) csio);
1094		return;
1095	}
1096
1097	r = wdsr_alloc(wp);
1098	if (r == NULL) {
1099		device_printf(wp->dev, "no request slot available!\n");
1100		wp->want_wdsr = 1;
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);
1105		return;
1106	}
1107
1108	ccb_h->ccb_wdsr = (void *) r;
1109	r->ccb = (union ccb *) csio;
1110
1111	switch (error = frag_alloc(wp, csio->dxfer_len, &r->buf, &r->mask)) {
1112	case CAM_REQ_CMP:
1113		break;
1114	case CAM_REQUEUE_REQ:
1115		DBG(DBX "wds%d: no data buffer available\n", unit);
1116		wp->want_wdsr = 1;
1117		n = xpt_freeze_simq(sim, /* count */ 1);
1118		smallog2('f', '0'+n);
1119		wdsr_ccb_done(wp, r, r->ccb, CAM_REQUEUE_REQ);
1120		return;
1121	default:
1122		DBG(DBX "wds%d: request is too big\n", unit);
1123		wdsr_ccb_done(wp, r, r->ccb, error);
1124		break;
1125	}
1126
1127	ccb_h->status |= CAM_SIM_QUEUED;
1128	r->flags &= ~WR_DONE;
1129
1130	scsi_ulto3b(WDSTOPHYS(wp, &r->cmd), wp->dx->ombs[r->ombn].addr);
1131
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;
1135
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);
1139	else
1140		bcopy(csio->cdb_io.cdb_bytes, &r->cmd.scb,
1141		      csio->cdb_len < 12 ? csio->cdb_len : 12);
1142
1143	scsi_ulto3b(csio->dxfer_len, r->cmd.len);
1144
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);
1149	}
1150	scsi_ulto3b(csio->dxfer_len ? WDSTOPHYS(wp, r->buf) : 0, r->cmd.data);
1151
1152	if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_IN)
1153		r->cmd.write = 0x80;
1154	else
1155		r->cmd.write = 0x00;
1156
1157	scsi_ulto3b(0, r->cmd.next);
1158
1159	bus_write_1(wp->port_r, WDS_HCR, WDSH_IRQEN | WDSH_DRQEN);
1160
1161	c = WDSC_MSTART(r->ombn);
1162
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);
1167		return;
1168	}
1169	DBG(DBX "wds%d: enqueued cmd 0x%x, r=%p\n", unit,
1170	    r->cmd.scb[0] & 0xFF, r);
1171
1172	smallog3('+', ccb_h->target_id + '0', ccb_h->target_lun + '0');
1173}
1174
1175static void
1176wds_action(struct cam_sim * sim, union ccb * ccb)
1177{
1178	int	unit = cam_sim_unit(sim);
1179
1180	DBG(DBX "wds%d: action 0x%x\n", unit, ccb->ccb_h.func_code);
1181	switch (ccb->ccb_h.func_code) {
1182	case XPT_SCSI_IO:
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);
1186		break;
1187	case XPT_RESET_BUS:
1188		/* how to do it right ? */
1189		printf("wds%d: reset\n", unit);
1190		ccb->ccb_h.status = CAM_REQ_CMP;
1191		xpt_done(ccb);
1192		break;
1193	case XPT_ABORT:
1194		ccb->ccb_h.status = CAM_UA_ABORT;
1195		xpt_done(ccb);
1196		break;
1197	case XPT_CALC_GEOMETRY:
1198	{
1199		struct	  ccb_calc_geometry *ccg;
1200		u_int32_t size_mb;
1201		u_int32_t secs_per_cylinder;
1202
1203		ccg = &ccb->ccg;
1204		size_mb = ccg->volume_size
1205			/ ((1024L * 1024L) / ccg->block_size);
1206
1207		ccg->heads = 64;
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;
1212		xpt_done(ccb);
1213		break;
1214	}
1215	case XPT_PATH_INQ:	/* Path routing inquiry */
1216	{
1217		struct ccb_pathinq *cpi = &ccb->cpi;
1218
1219		cpi->version_num = 1;	/* XXX??? */
1220		cpi->hba_inquiry = 0;	/* nothing fancy */
1221		cpi->target_sprt = 0;
1222		cpi->hba_misc = 0;
1223		cpi->hba_eng_cnt = 0;
1224		cpi->max_target = 7;
1225		cpi->max_lun = 7;
1226		cpi->initiator_id = WDS_HBA_ID;
1227		cpi->hba_misc = 0;
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;
1235		xpt_done(ccb);
1236		break;
1237	}
1238	default:
1239		ccb->ccb_h.status = CAM_REQ_INVALID;
1240		xpt_done(ccb);
1241		break;
1242	}
1243}
1244
1245static void
1246wds_poll(struct cam_sim * sim)
1247{
1248	wds_intr_locked(cam_sim_softc(sim));
1249}
1250
1251/* part of initialization done in probe() */
1252/* returns 0 if OK, ENXIO if bad */
1253
1254static int
1255wds_preinit(struct wds *wp)
1256{
1257	int	i;
1258
1259	/*
1260	 * Sending a command causes the CMDRDY bit to clear.
1261	 */
1262	bus_write_1(wp->port_r, WDS_CMD, WDSC_NOOP);
1263	if (bus_read_1(wp->port_r, WDS_STAT) & WDS_RDY)
1264		return (ENXIO);
1265
1266	/*
1267	 * the controller exists. reset and init.
1268	 */
1269	bus_write_1(wp->port_r, WDS_HCR, WDSH_ASCRESET | WDSH_SCSIRESET);
1270	DELAY(30);
1271	bus_write_1(wp->port_r, WDS_HCR, 0);
1272
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)
1276				break;
1277			DELAY(40000);
1278		}
1279		if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY)
1280			/* probe timeout */
1281			return (ENXIO);
1282	}
1283
1284	return (0);
1285}
1286
1287/* part of initialization done in attach() */
1288/* returns 0 if OK, 1 if bad */
1289
1290static int
1291wds_init(struct wds *wp)
1292{
1293	struct	wds_setup init;
1294	int	i;
1295	struct	wds_cmd  wc;
1296
1297	bus_write_1(wp->port_r, WDS_HCR, WDSH_DRQEN);
1298
1299	isa_dmacascade(wp->drq);
1300
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)
1304				break;
1305			DELAY(40000);
1306		}
1307		if ((bus_read_1(wp->port_r, WDS_STAT) & (WDS_RDY)) != WDS_RDY)
1308			/* probe timeout */
1309			return (1);
1310	}
1311	bzero(&init, sizeof init);
1312	init.cmd = WDSC_INIT;
1313	init.scsi_id = WDS_HBA_ID;
1314	init.buson_t = 24;
1315	init.busoff_t = 48;
1316	scsi_ulto3b(WDSTOPHYS(wp, &wp->dx->ombs), init.mbaddr);
1317	init.xx = 0;
1318	init.nomb = WDS_NOMB;
1319	init.nimb = WDS_NIMB;
1320
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");
1324		return (1);
1325	}
1326	wds_wait(wp, WDS_STAT, WDS_INIT, WDS_INIT);
1327
1328	wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
1329
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");
1334		return (1);
1335	}
1336	return (0);
1337}
1338
1339static int
1340wds_cmd(struct wds *wp, u_int8_t * p, int l)
1341{
1342
1343	while (l--) {
1344		do {
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);
1348		p++;
1349	}
1350
1351	wds_wait(wp, WDS_STAT, WDS_RDY, WDS_RDY);
1352
1353	return (0);
1354}
1355
1356static void
1357wds_wait(struct wds *wp, int reg, int mask, int val)
1358{
1359	while ((bus_read_1(wp->port_r, reg) & mask) != val)
1360		;
1361}
1362
1363static struct wds_req *
1364cmdtovirt(struct wds *wp, u_int32_t phys)
1365{
1366	char	*a;
1367
1368	a = WDSTOVIRT(wp, (uintptr_t)phys);
1369	if( a < (char *)&wp->dx->req[0] || a>= (char *)&wp->dx->req[MAXSIMUL]) {
1370		device_printf(wp->dev, "weird phys address 0x%x\n", phys);
1371		return (NULL);
1372	}
1373	a -= (int)offsetof(struct wds_req, cmd); /* convert cmd to request */
1374	return ((struct wds_req *)a);
1375}
1376
1377/* for debugging, print out all the data about the status of devices */
1378void
1379wds_print(void)
1380{
1381	int	unit;
1382	int	i;
1383	struct	wds_req *r;
1384	struct	wds     *wp;
1385
1386	for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) {
1387		wp = (struct wds *) devclass_get_device(wds_devclass, unit);
1388		if (wp == NULL)
1389			continue;
1390		printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n",
1391		       unit, wp->want_wdsr, 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]);
1403			}
1404		}
1405	}
1406}
1407
1408#if WDS_DEBUG == 2
1409/* create circular log buffer */
1410static char    *
1411wds_nextlog(void)
1412{
1413	int	n = logwrite;
1414
1415	if (++logwrite >= NLOGLINES)
1416		logwrite = 0;
1417	if (logread == logwrite)
1418		if (++logread >= NLOGLINES)
1419			logread = 0;
1420	return (wds_log[n]);
1421}
1422
1423void
1424wds_printlog(void)
1425{
1426	/* print the circular buffer */
1427	int	i;
1428
1429	for (i = logread; i != logwrite;) {
1430		printf("%s", wds_log[i]);
1431		if (i == NLOGLINES)
1432			i = 0;
1433		else
1434			i++;
1435	}
1436}
1437#endif /* WDS_DEBUG */
1438