xref: /NextBSD/sys/dev/wds/wd7000.c (revision 4bf303e5af1834cdd3092175eeca7676420229c4)
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 
210 struct 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 
223 struct 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 
253 struct 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 
269 struct 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 
285 static int	fragsiz;
286 static int	nfrags;
287 
288 /* structure for data exchange with controller */
289 
290 struct 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 
299 struct 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 
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);
328 
329 static void     wds_action(struct cam_sim * sim, union ccb * ccb);
330 static void     wds_poll(struct cam_sim * sim);
331 
332 static int      wds_preinit(struct wds *wp);
333 static int      wds_init(struct wds *wp);
334 
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);
338 
339 static struct wds_req *wdsr_alloc(struct wds *wp);
340 
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);
344 
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);
348 
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);
351 
352 static struct wds_req *cmdtovirt(struct wds *wp, u_int32_t phys);
353 
354 static u_int32_t frag_alloc(struct wds *wp, int size, u_int8_t **res,
355 			    u_int32_t *maskp);
356 static void     frag_free(struct wds *wp, u_int32_t mask);
357 
358 void            wds_print(void);
359 
360 #if WDS_ENABLE_SMALLOG==1
361 static __inline void   smallog(char c);
362 void 	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 
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);
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 */
390 static device_method_t wds_isa_methods[] = {
391 	DEVMETHOD(device_probe,		wds_probe),
392 	DEVMETHOD(device_attach,	wds_attach),
393 	{ 0, 0 }
394 };
395 
396 static driver_t wds_isa_driver = {
397 	"wds",
398 	wds_isa_methods,
399 	sizeof(struct wds),
400 };
401 
402 static devclass_t wds_devclass;
403 
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);
407 
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;
413 
414 static __inline void
smallog(char c)415 smallog(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 
428 void
wds_printsmallog(void)429 wds_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 
455 static int
wds_probe(device_t dev)456 wds_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 
511 static int
wds_attach(device_t dev)512 wds_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 
633 bad:
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 */
643 static void
wds_alloc_callback(void * arg,bus_dma_segment_t * seg,int nseg,int error)644 wds_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 
649 static void
wds_free_resources(struct wds * wp)650 wds_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 */
690 static u_int32_t
frag_alloc(struct wds * wp,int size,u_int8_t ** res,u_int32_t * maskp)691 frag_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 
725 static void
frag_free(struct wds * wp,u_int32_t mask)726 frag_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 
732 static struct wds_req *
wdsr_alloc(struct wds * wp)733 wdsr_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 
763 static void
wds_intr(void * arg)764 wds_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 
774 static void
wds_intr_locked(struct wds * wp)775 wds_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 
813 static void
wds_done(struct wds * wp,struct wds_req * r,u_int8_t stat)814 wds_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 
923 static int
wds_runsense(struct wds * wp,struct wds_req * r)924 wds_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 
969 static int
wds_getvers(struct wds * wp)970 wds_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 
1018 static void
wdsr_ccb_done(struct wds * wp,struct wds_req * r,union ccb * ccb,u_int32_t status)1019 wdsr_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 
1044 static void
wds_scsi_io(struct cam_sim * sim,struct ccb_scsiio * csio)1045 wds_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 
1175 static void
wds_action(struct cam_sim * sim,union ccb * ccb)1176 wds_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 
1245 static void
wds_poll(struct cam_sim * sim)1246 wds_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 
1254 static int
wds_preinit(struct wds * wp)1255 wds_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 
1290 static int
wds_init(struct wds * wp)1291 wds_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 
1339 static int
wds_cmd(struct wds * wp,u_int8_t * p,int l)1340 wds_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 
1356 static void
wds_wait(struct wds * wp,int reg,int mask,int val)1357 wds_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 
1363 static struct wds_req *
cmdtovirt(struct wds * wp,u_int32_t phys)1364 cmdtovirt(struct wds *wp, u_int32_t phys)
1365 {
1366 	char	*a;
1367 
1368 	a = WDSTOVIRT(wp, (uintptr_t)phys);
1369 	if( a < (char *)&wp->dx->req[0] || a>= (char *)&wp->dx->req[MAXSIMUL]) {
1370 		device_printf(wp->dev, "weird phys address 0x%x\n", phys);
1371 		return (NULL);
1372 	}
1373 	a -= (int)offsetof(struct wds_req, cmd); /* convert cmd to request */
1374 	return ((struct wds_req *)a);
1375 }
1376 
1377 /* for debugging, print out all the data about the status of devices */
1378 void
wds_print(void)1379 wds_print(void)
1380 {
1381 	int	unit;
1382 	int	i;
1383 	struct	wds_req *r;
1384 	struct	wds     *wp;
1385 
1386 	for (unit = 0; unit < devclass_get_maxunit(wds_devclass); unit++) {
1387 		wp = (struct wds *) devclass_get_device(wds_devclass, unit);
1388 		if (wp == NULL)
1389 			continue;
1390 		printf("wds%d: want_wdsr=0x%x stat=0x%x irq=%s irqstat=0x%x\n",
1391 		       unit, wp->want_wdsr, 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 */
1410 static char    *
wds_nextlog(void)1411 wds_nextlog(void)
1412 {
1413 	int	n = logwrite;
1414 
1415 	if (++logwrite >= NLOGLINES)
1416 		logwrite = 0;
1417 	if (logread == logwrite)
1418 		if (++logread >= NLOGLINES)
1419 			logread = 0;
1420 	return (wds_log[n]);
1421 }
1422 
1423 void
wds_printlog(void)1424 wds_printlog(void)
1425 {
1426 	/* print the circular buffer */
1427 	int	i;
1428 
1429 	for (i = logread; i != logwrite;) {
1430 		printf("%s", wds_log[i]);
1431 		if (i == NLOGLINES)
1432 			i = 0;
1433 		else
1434 			i++;
1435 	}
1436 }
1437 #endif /* WDS_DEBUG */
1438