xref: /openbsd-src/sys/dev/ic/cac.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: cac.c,v 1.48 2011/07/17 22:46:48 matthew Exp $	*/
2 /*	$NetBSD: cac.c,v 1.15 2000/11/08 19:20:35 ad Exp $	*/
3 
4 /*
5  * Copyright (c) 2001,2003 Michael Shalayeff
6  * All rights reserved.
7  *
8  * The SCSI emulation layer is derived from gdt(4) driver,
9  * Copyright (c) 1999, 2000 Niklas Hallqvist. All rights reserved.
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  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 /*-
33  * Copyright (c) 2000 The NetBSD Foundation, Inc.
34  * All rights reserved.
35  *
36  * This code is derived from software contributed to The NetBSD Foundation
37  * by Andrew Doran.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  *
48  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
49  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
50  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
51  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
52  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
53  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
54  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
55  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
56  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
57  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
58  * POSSIBILITY OF SUCH DAMAGE.
59  */
60 
61 /*
62  * Driver for Compaq array controllers.
63  */
64 
65 #include "bio.h"
66 
67 /* #define	CAC_DEBUG */
68 
69 #include <sys/param.h>
70 #include <sys/systm.h>
71 #include <sys/kernel.h>
72 #include <sys/ioctl.h>
73 #include <sys/device.h>
74 #include <sys/queue.h>
75 #include <sys/proc.h>
76 #include <sys/buf.h>
77 #include <sys/endian.h>
78 #include <sys/malloc.h>
79 #include <sys/pool.h>
80 
81 #include <machine/bus.h>
82 
83 #include <scsi/scsi_all.h>
84 #include <scsi/scsi_disk.h>
85 #include <scsi/scsiconf.h>
86 
87 #include <dev/ic/cacreg.h>
88 #include <dev/ic/cacvar.h>
89 
90 #if NBIO > 0
91 #include <dev/biovar.h>
92 #endif
93 #include <sys/sensors.h>
94 
95 struct cfdriver cac_cd = {
96 	NULL, "cac", DV_DULL
97 };
98 
99 void    cac_scsi_cmd(struct scsi_xfer *);
100 void	cacminphys(struct buf *bp, struct scsi_link *sl);
101 
102 struct scsi_adapter cac_switch = {
103 	cac_scsi_cmd, cacminphys, 0, 0,
104 };
105 
106 void	*cac_ccb_alloc(void *);
107 void	cac_ccb_done(struct cac_softc *, struct cac_ccb *);
108 void	cac_ccb_free(void *, void *);
109 int	cac_ccb_poll(struct cac_softc *, struct cac_ccb *, int);
110 int	cac_ccb_start(struct cac_softc *, struct cac_ccb *);
111 int	cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
112 	int drive, int blkno, int flags, struct scsi_xfer *xs);
113 int	cac_get_dinfo(struct cac_softc *sc, int target);
114 int	cac_flush(struct cac_softc *sc);
115 void	cac_shutdown(void *);
116 void	cac_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size);
117 
118 struct	cac_ccb *cac_l0_completed(struct cac_softc *);
119 int	cac_l0_fifo_full(struct cac_softc *);
120 void	cac_l0_intr_enable(struct cac_softc *, int);
121 int	cac_l0_intr_pending(struct cac_softc *);
122 void	cac_l0_submit(struct cac_softc *, struct cac_ccb *);
123 
124 #if NBIO > 0
125 int	cac_ioctl(struct device *, u_long, caddr_t);
126 int	cac_ioctl_vol(struct cac_softc *, struct bioc_vol *);
127 
128 #ifndef SMALL_KERNEL
129 int	cac_create_sensors(struct cac_softc *);
130 void	cac_sensor_refresh(void *);
131 #endif
132 #endif /* NBIO > 0 */
133 
134 void	*cac_sdh;	/* shutdown hook */
135 
136 const
137 struct cac_linkage cac_l0 = {
138 	cac_l0_completed,
139 	cac_l0_fifo_full,
140 	cac_l0_intr_enable,
141 	cac_l0_intr_pending,
142 	cac_l0_submit
143 };
144 
145 /*
146  * Initialise our interface to the controller.
147  */
148 int
149 cac_init(struct cac_softc *sc, int startfw)
150 {
151 	struct scsibus_attach_args saa;
152 	struct cac_controller_info cinfo;
153 	int error, rseg, size, i;
154 	bus_dma_segment_t seg[1];
155 	struct cac_ccb *ccb;
156 
157 	SIMPLEQ_INIT(&sc->sc_ccb_free);
158 	SIMPLEQ_INIT(&sc->sc_ccb_queue);
159 	mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
160 	scsi_iopool_init(&sc->sc_iopool, sc, cac_ccb_alloc, cac_ccb_free);
161 
162         size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
163 
164 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1,
165 	    &rseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0) {
166 		printf("%s: unable to allocate CCBs, error = %d\n",
167 		    sc->sc_dv.dv_xname, error);
168 		return (-1);
169 	}
170 
171 	if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size,
172 	    &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
173 		printf("%s: unable to map CCBs, error = %d\n",
174 		    sc->sc_dv.dv_xname, error);
175 		return (-1);
176 	}
177 
178 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
179 	    BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
180 		printf("%s: unable to create CCB DMA map, error = %d\n",
181 		    sc->sc_dv.dv_xname, error);
182 		return (-1);
183 	}
184 
185 	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
186 	    size, NULL, BUS_DMA_NOWAIT)) != 0) {
187 		printf("%s: unable to load CCB DMA map, error = %d\n",
188 		    sc->sc_dv.dv_xname, error);
189 		return (-1);
190 	}
191 
192 	sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
193 	ccb = (struct cac_ccb *)sc->sc_ccbs;
194 
195 	for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
196 		/* Create the DMA map for this CCB's data */
197 		error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
198 		    CAC_SG_SIZE, CAC_MAX_XFER, 0,
199 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
200 		    &ccb->ccb_dmamap_xfer);
201 
202 		if (error) {
203 			printf("%s: can't create ccb dmamap (%d)\n",
204 			    sc->sc_dv.dv_xname, error);
205 			break;
206 		}
207 
208 		ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
209 		mtx_enter(&sc->sc_ccb_mtx);
210 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
211 		mtx_leave(&sc->sc_ccb_mtx);
212 	}
213 
214 	/* Start firmware background tasks, if needed. */
215 	if (startfw) {
216 		if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
217 		    0, 0, CAC_CCB_DATA_IN, NULL)) {
218 			printf("%s: CAC_CMD_START_FIRMWARE failed\n",
219 			    sc->sc_dv.dv_xname);
220 			return (-1);
221 		}
222 	}
223 
224 	if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
225 	    CAC_CCB_DATA_IN, NULL)) {
226 		printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
227 		    sc->sc_dv.dv_xname);
228 		return (-1);
229 	}
230 
231 	if (!cinfo.num_drvs) {
232 		printf("%s: no volumes defined\n", sc->sc_dv.dv_xname);
233 		return (-1);
234 	}
235 
236 	sc->sc_nunits = cinfo.num_drvs;
237 	sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info),
238 	    M_DEVBUF, M_NOWAIT | M_ZERO);
239 	if (sc->sc_dinfos == NULL) {
240 		printf("%s: cannot allocate memory for drive_info\n",
241 		    sc->sc_dv.dv_xname);
242 		return (-1);
243 	}
244 
245 	sc->sc_link.adapter_softc = sc;
246 	sc->sc_link.adapter = &cac_switch;
247 	sc->sc_link.adapter_target = cinfo.num_drvs;
248 	sc->sc_link.adapter_buswidth = cinfo.num_drvs;
249 	sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits;
250 	if (sc->sc_link.openings < 4 )
251 		sc->sc_link.openings = 4;
252 	sc->sc_link.pool = &sc->sc_iopool;
253 
254 	bzero(&saa, sizeof(saa));
255 	saa.saa_sc_link = &sc->sc_link;
256 
257 	config_found(&sc->sc_dv, &saa, scsiprint);
258 
259 	/* Set our `shutdownhook' before we start any device activity. */
260 	if (cac_sdh == NULL)
261 		cac_sdh = shutdownhook_establish(cac_shutdown, NULL);
262 
263 	(*sc->sc_cl->cl_intr_enable)(sc, 1);
264 
265 #if NBIO > 0
266 	if (bio_register(&sc->sc_dv, cac_ioctl) != 0)
267 		printf("%s: controller registration failed\n",
268 		    sc->sc_dv.dv_xname);
269 	else
270 		sc->sc_ioctl = cac_ioctl;
271 
272 #ifndef SMALL_KERNEL
273 	if (cac_create_sensors(sc) != 0)
274 		printf("%s: unable to create sensors\n", sc->sc_dv.dv_xname);
275 #endif
276 #endif
277 
278 
279 	return (0);
280 }
281 
282 int
283 cac_flush(sc)
284 	struct cac_softc *sc;
285 {
286 	u_int8_t buf[512];
287 
288 	memset(buf, 0, sizeof(buf));
289 	buf[0] = 1;
290 	return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
291 	    CAC_CCB_DATA_OUT, NULL);
292 }
293 
294 /*
295  * Shut down all `cac' controllers.
296  */
297 void
298 cac_shutdown(void *cookie)
299 {
300 	extern struct cfdriver cac_cd;
301 	struct cac_softc *sc;
302 	int i;
303 
304 	for (i = 0; i < cac_cd.cd_ndevs; i++) {
305 		if ((sc = (struct cac_softc *)device_lookup(&cac_cd, i)) == NULL)
306 			continue;
307 		cac_flush(sc);
308 	}
309 }
310 
311 /*
312  * Handle an interrupt from the controller: process finished CCBs and
313  * dequeue any waiting CCBs.
314  */
315 int
316 cac_intr(v)
317 	void *v;
318 {
319 	struct cac_softc *sc = v;
320 	struct cac_ccb *ccb;
321 	int istat, ret = 0;
322 
323 	if (!(istat = (*sc->sc_cl->cl_intr_pending)(sc)))
324 		return 0;
325 
326 	if (istat & CAC_INTR_FIFO_NEMPTY)
327 		while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) {
328 			ret = 1;
329 			cac_ccb_done(sc, ccb);
330 		}
331 	cac_ccb_start(sc, NULL);
332 
333 	return (ret);
334 }
335 
336 /*
337  * Execute a [polled] command.
338  */
339 int
340 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
341 	int drive, int blkno, int flags, struct scsi_xfer *xs)
342 {
343 	struct cac_ccb *ccb;
344 	struct cac_sgb *sgb;
345 	int i, rv, size, nsegs;
346 
347 #ifdef CAC_DEBUG
348 	printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ",
349 	    command, drive, blkno, data, datasize, flags, xs);
350 #endif
351 
352 	if (xs) {
353 		ccb = xs->io;
354 		/*
355 		 * The xs may have been restarted by the scsi layer, so
356 		 * ensure the ccb starts in the proper state.
357 		 */
358 		ccb->ccb_flags = 0;
359 	} else {
360 		/* Internal command. Need to get our own ccb. */
361 		ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL | SCSI_NOSLEEP);
362 		if (ccb == NULL)
363 			return (EBUSY);
364 	}
365 
366 	if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
367 		bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
368 		    (void *)data, datasize, NULL, BUS_DMA_NOWAIT);
369 
370 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
371 		    ccb->ccb_dmamap_xfer->dm_mapsize,
372 		    (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
373 		    BUS_DMASYNC_PREWRITE);
374 
375 		sgb = ccb->ccb_seg;
376 		nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
377 		if (nsegs > CAC_SG_SIZE)
378 			panic("cac_cmd: nsegs botch");
379 
380 		size = 0;
381 		for (i = 0; i < nsegs; i++, sgb++) {
382 			size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
383 			sgb->length =
384 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
385 			sgb->addr =
386 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
387 		}
388 	} else {
389 		size = datasize;
390 		nsegs = 0;
391 	}
392 
393 	ccb->ccb_hdr.drive = drive;
394 	ccb->ccb_hdr.priority = 0;
395 	ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
396 	    sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
397 
398 	ccb->ccb_req.next = 0;
399 	ccb->ccb_req.command = command;
400 	ccb->ccb_req.error = 0;
401 	ccb->ccb_req.blkno = htole32(blkno);
402 	ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
403 	ccb->ccb_req.sgcount = nsegs;
404 	ccb->ccb_req.reserved = 0;
405 
406 	ccb->ccb_flags = flags;
407 	ccb->ccb_datasize = size;
408 	ccb->ccb_xs = xs;
409 
410 	if (!xs || xs->flags & SCSI_POLL) {
411 		/* Synchronous commands musn't wait. */
412 		mtx_enter(&sc->sc_ccb_mtx);
413 		if ((*sc->sc_cl->cl_fifo_full)(sc)) {
414 			mtx_leave(&sc->sc_ccb_mtx);
415 			rv = EBUSY;
416 		} else {
417 			mtx_leave(&sc->sc_ccb_mtx);
418 			ccb->ccb_flags |= CAC_CCB_ACTIVE;
419 			(*sc->sc_cl->cl_submit)(sc, ccb);
420 			rv = cac_ccb_poll(sc, ccb, 2000);
421 		}
422 	} else
423 		rv = cac_ccb_start(sc, ccb);
424 
425 	if (xs == NULL)
426 		scsi_io_put(&sc->sc_iopool, ccb);
427 
428 	return (rv);
429 }
430 
431 /*
432  * Wait for the specified CCB to complete.  Must be called at splbio.
433  */
434 int
435 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
436 {
437 	struct cac_ccb *ccb;
438 	int t;
439 
440 	t = timo * 100;
441 	do {
442 		for (; t--; DELAY(10))
443 			if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
444 				break;
445 		if (t < 0) {
446 			printf("%s: timeout\n", sc->sc_dv.dv_xname);
447 			return (EBUSY);
448 		}
449 		cac_ccb_done(sc, ccb);
450 	} while (ccb != wantccb);
451 
452 	return (0);
453 }
454 
455 /*
456  * Enqueue the specified command (if any) and attempt to start all enqueued
457  * commands.
458  */
459 int
460 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
461 {
462 	if (ccb != NULL) {
463 		mtx_enter(&sc->sc_ccb_mtx);
464 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
465 		mtx_leave(&sc->sc_ccb_mtx);
466 	}
467 
468 	while (1) {
469 		mtx_enter(&sc->sc_ccb_mtx);
470 		if (SIMPLEQ_EMPTY(&sc->sc_ccb_queue) ||
471 		    (*sc->sc_cl->cl_fifo_full)(sc)) {
472 			mtx_leave(&sc->sc_ccb_mtx);
473 			break;
474 		}
475 		ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue);
476 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
477 		mtx_leave(&sc->sc_ccb_mtx);
478 
479 		ccb->ccb_flags |= CAC_CCB_ACTIVE;
480 		(*sc->sc_cl->cl_submit)(sc, ccb);
481 	}
482 
483 	return (0);
484 }
485 
486 /*
487  * Process a finished CCB.
488  */
489 void
490 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
491 {
492 	struct scsi_xfer *xs = ccb->ccb_xs;
493 	int error = 0;
494 
495 	if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) {
496 		printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs);
497 		if (xs) {
498 			xs->error = XS_DRIVER_STUFFUP;
499 			scsi_done(xs);
500 		}
501 		return;
502 	}
503 
504 	if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
505 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
506 		    ccb->ccb_dmamap_xfer->dm_mapsize,
507 		    ccb->ccb_flags & CAC_CCB_DATA_IN ?
508 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
509 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
510 	}
511 
512 	if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
513 		printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname);
514 	if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
515 		error = 1;
516 		printf("%s: hard error\n", sc->sc_dv.dv_xname);
517 	}
518 	if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
519 		error = 1;
520 		printf("%s: invalid request\n", sc->sc_dv.dv_xname);
521 	}
522 
523 	if (xs) {
524 		if (error)
525 			xs->error = XS_DRIVER_STUFFUP;
526 		else
527 			xs->resid = 0;
528 
529 		scsi_done(xs);
530 	}
531 }
532 
533 /*
534  * Allocate a CCB.
535  */
536 void *
537 cac_ccb_alloc(void *xsc)
538 {
539 	struct cac_softc *sc = xsc;
540 	struct cac_ccb *ccb = NULL;
541 
542 	mtx_enter(&sc->sc_ccb_mtx);
543 	if (SIMPLEQ_EMPTY(&sc->sc_ccb_free)) {
544 #ifdef CAC_DEBUG
545 		printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
546 #endif
547 	} else {
548 		ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free);
549 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
550 	}
551 	mtx_leave(&sc->sc_ccb_mtx);
552 
553 	return (ccb);
554 }
555 
556 /*
557  * Put a CCB onto the freelist.
558  */
559 void
560 cac_ccb_free(void *xsc, void *xccb)
561 {
562 	struct cac_softc *sc = xsc;
563 	struct cac_ccb *ccb = xccb;
564 
565 	ccb->ccb_flags = 0;
566 
567 	mtx_enter(&sc->sc_ccb_mtx);
568 	SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
569 	mtx_leave(&sc->sc_ccb_mtx);
570 }
571 
572 int
573 cac_get_dinfo(sc, target)
574 	struct cac_softc *sc;
575 	int target;
576 {
577 	if (sc->sc_dinfos[target].ncylinders)
578 		return (0);
579 
580 	if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target],
581 	    sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) {
582 		printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
583 		    sc->sc_dv.dv_xname);
584 		return (-1);
585 	}
586 
587 	return (0);
588 }
589 
590 void
591 cacminphys(struct buf *bp, struct scsi_link *sl)
592 {
593 	if (bp->b_bcount > CAC_MAX_XFER)
594 		bp->b_bcount = CAC_MAX_XFER;
595 	minphys(bp);
596 }
597 
598 void
599 cac_copy_internal_data(xs, v, size)
600 	struct scsi_xfer *xs;
601 	void *v;
602 	size_t size;
603 {
604 	size_t copy_cnt;
605 
606 	if (!xs->datalen)
607 		printf("uio move is not yet supported\n");
608 	else {
609 		copy_cnt = MIN(size, xs->datalen);
610 		bcopy(v, xs->data, copy_cnt);
611 	}
612 }
613 
614 void
615 cac_scsi_cmd(xs)
616 	struct scsi_xfer *xs;
617 {
618 	struct scsi_link *link = xs->sc_link;
619 	struct cac_softc *sc = link->adapter_softc;
620 	struct cac_drive_info *dinfo;
621 	struct scsi_inquiry_data inq;
622 	struct scsi_sense_data sd;
623 	struct scsi_read_cap_data rcd;
624 	u_int8_t target = link->target;
625 	u_int32_t blockno, blockcnt, size;
626 	struct scsi_rw *rw;
627 	struct scsi_rw_big *rwb;
628 	int op, flags, s, error;
629 	const char *p;
630 
631 	if (target >= sc->sc_nunits || link->lun != 0) {
632 		xs->error = XS_DRIVER_STUFFUP;
633 		scsi_done(xs);
634 		return;
635 	}
636 
637 	s = splbio();
638 	xs->error = XS_NOERROR;
639 	dinfo = &sc->sc_dinfos[target];
640 
641 	switch (xs->cmd->opcode) {
642 	case TEST_UNIT_READY:
643 	case START_STOP:
644 #if 0
645 	case VERIFY:
646 #endif
647 		break;
648 
649 	case REQUEST_SENSE:
650 		bzero(&sd, sizeof sd);
651 		sd.error_code = SSD_ERRCODE_CURRENT;
652 		sd.segment = 0;
653 		sd.flags = SKEY_NO_SENSE;
654 		*(u_int32_t*)sd.info = htole32(0);
655 		sd.extra_len = 0;
656 		cac_copy_internal_data(xs, &sd, sizeof sd);
657 		break;
658 
659 	case INQUIRY:
660 		if (cac_get_dinfo(sc, target)) {
661 			xs->error = XS_DRIVER_STUFFUP;
662 			break;
663 		}
664 		bzero(&inq, sizeof inq);
665 		inq.device = T_DIRECT;
666 		inq.dev_qual2 = 0;
667 		inq.version = 2;
668 		inq.response_format = 2;
669 		inq.additional_length = 32;
670 		inq.flags |= SID_CmdQue;
671 		strlcpy(inq.vendor, "Compaq  ", sizeof inq.vendor);
672 		switch (CAC_GET1(dinfo->mirror)) {
673 		case 0: p = "RAID0";	break;
674 		case 1: p = "RAID4";	break;
675 		case 2: p = "RAID1";	break;
676 		case 3: p = "RAID5";	break;
677 		default:p = "<UNK>";	break;
678 		}
679 		snprintf(inq.product, sizeof inq.product, "%s vol  #%02d",
680 		    p, target);
681 		strlcpy(inq.revision, "   ", sizeof inq.revision);
682 		cac_copy_internal_data(xs, &inq, sizeof inq);
683 		break;
684 
685 	case READ_CAPACITY:
686 		if (cac_get_dinfo(sc, target)) {
687 			xs->error = XS_DRIVER_STUFFUP;
688 			break;
689 		}
690 		bzero(&rcd, sizeof rcd);
691 		_lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
692 		    CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
693 		_lto4b(CAC_SECTOR_SIZE, rcd.length);
694 		cac_copy_internal_data(xs, &rcd, sizeof rcd);
695 		break;
696 
697 	case PREVENT_ALLOW:
698 		break;
699 
700 	case SYNCHRONIZE_CACHE:
701 		if (cac_flush(sc))
702 			xs->error = XS_DRIVER_STUFFUP;
703 		break;
704 
705 	case READ_COMMAND:
706 	case READ_BIG:
707 	case WRITE_COMMAND:
708 	case WRITE_BIG:
709 
710 		flags = 0;
711 		/* A read or write operation. */
712 		if (xs->cmdlen == 6) {
713 			rw = (struct scsi_rw *)xs->cmd;
714 			blockno = _3btol(rw->addr) &
715 			    (SRW_TOPADDR << 16 | 0xffff);
716 			blockcnt = rw->length ? rw->length : 0x100;
717 		} else {
718 			rwb = (struct scsi_rw_big *)xs->cmd;
719 			blockno = _4btol(rwb->addr);
720 			blockcnt = _2btol(rwb->length);
721 		}
722 		size = CAC_GET2(dinfo->ncylinders) *
723 		    CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
724 		if (blockno >= size || blockno + blockcnt > size) {
725 			printf("%s: out of bounds %u-%u >= %u\n",
726 			    sc->sc_dv.dv_xname, blockno, blockcnt, size);
727 			xs->error = XS_DRIVER_STUFFUP;
728 			break;
729 		}
730 
731 		switch (xs->cmd->opcode) {
732 		case READ_COMMAND:
733 		case READ_BIG:
734 			op = CAC_CMD_READ;
735 			flags = CAC_CCB_DATA_IN;
736 			break;
737 		case WRITE_COMMAND:
738 		case WRITE_BIG:
739 			op = CAC_CMD_WRITE;
740 			flags = CAC_CCB_DATA_OUT;
741 			break;
742 		}
743 
744 		if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
745 		    target, blockno, flags, xs))) {
746 			splx(s);
747 			if (error == EBUSY)
748 				xs->error = XS_BUSY;
749 			else
750 				xs->error = XS_DRIVER_STUFFUP;
751 			scsi_done(xs);
752 			return;
753 		}
754 
755 		splx(s);
756 		return;
757 
758 	default:
759 		SC_DEBUG(link, SDEV_DB1, ("unsupported scsi command %#x "
760 		    "tgt %d ", xs->cmd->opcode, target));
761 		xs->error = XS_DRIVER_STUFFUP;
762 	}
763 
764 	splx(s);
765 	scsi_done(xs);
766 }
767 
768 /*
769  * Board specific linkage shared between multiple bus types.
770  */
771 
772 int
773 cac_l0_fifo_full(struct cac_softc *sc)
774 {
775 
776 	return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
777 }
778 
779 void
780 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
781 {
782 #ifdef CAC_DEBUG
783 	printf("submit-%x ", ccb->ccb_paddr);
784 #endif
785 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
786 	    sc->sc_dmamap->dm_mapsize,
787 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
788 	cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
789 }
790 
791 struct cac_ccb *
792 cac_l0_completed(sc)
793 	struct cac_softc *sc;
794 {
795 	struct cac_ccb *ccb;
796 	paddr_t off;
797 
798 	if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
799 		return NULL;
800 #ifdef CAC_DEBUG
801 	printf("compl-%x ", off);
802 #endif
803 	if (off & 3 && ccb->ccb_req.error == 0)
804 		ccb->ccb_req.error = CAC_RET_CMD_INVALID;
805 
806 	off = (off & ~3) - sc->sc_ccbs_paddr;
807 	ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
808 
809 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
810 	    sc->sc_dmamap->dm_mapsize,
811 	    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
812 
813 	return (ccb);
814 }
815 
816 int
817 cac_l0_intr_pending(struct cac_softc *sc)
818 {
819 
820 	return (cac_inl(sc, CAC_REG_INTR_PENDING));
821 }
822 
823 void
824 cac_l0_intr_enable(struct cac_softc *sc, int state)
825 {
826 
827 	cac_outl(sc, CAC_REG_INTR_MASK,
828 	    state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
829 }
830 
831 #if NBIO > 0
832 const int cac_level[] = { 0, 4, 1, 5, 51, 7 };
833 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
834     BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
835     BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
836     BIOC_SVOFFLINE, BIOC_SVBUILDING };
837 
838 int
839 cac_ioctl(struct device *dev, u_long cmd, caddr_t addr)
840 {
841 	struct cac_softc *sc = (struct cac_softc *)dev;
842 	struct bioc_inq *bi;
843 	struct bioc_disk *bd;
844 	cac_lock_t lock;
845 	int error = 0;
846 
847 	lock = CAC_LOCK(sc);
848 	switch (cmd) {
849 	case BIOCINQ:
850 		bi = (struct bioc_inq *)addr;
851 		strlcpy(bi->bi_dev, sc->sc_dv.dv_xname, sizeof(bi->bi_dev));
852 		bi->bi_novol = sc->sc_nunits;
853 		bi->bi_nodisk = 0;
854 		break;
855 
856 	case BIOCVOL:
857 		error = cac_ioctl_vol(sc, (struct bioc_vol *)addr);
858 		break;
859 
860 	case BIOCDISK:
861 		bd = (struct bioc_disk *)addr;
862 		if (bd->bd_volid > sc->sc_nunits) {
863 			error = EINVAL;
864 			break;
865 		}
866 		/* No disk information yet */
867 		break;
868 
869 	case BIOCBLINK:
870 	case BIOCALARM:
871 	case BIOCSETSTATE:
872 	default:
873 		error = ENOTTY;
874 	}
875 	CAC_UNLOCK(sc, lock);
876 
877 	return (error);
878 }
879 
880 int
881 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv)
882 {
883 	struct cac_drive_info dinfo;
884 	struct cac_drive_status dstatus;
885 	u_int32_t blks;
886 
887 	if (bv->bv_volid > sc->sc_nunits)
888 		return (EINVAL);
889 	if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo),
890 	    bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
891 		return (EIO);
892 	if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus),
893 	    bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
894 		return (EIO);
895 	bv->bv_status = BIOC_SVINVALID;
896 	blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) *
897 	    CAC_GET1(dinfo.nsectors);
898 	bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize);
899 	bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)];	/*XXX limit check */
900 	bv->bv_nodisk = 0;		/* XXX */
901 	bv->bv_status = 0;		/* XXX */
902 	bv->bv_percent = -1;
903 	bv->bv_seconds = 0;
904 	if (dstatus.stat < nitems(cac_stat))
905 		bv->bv_status = cac_stat[dstatus.stat];
906 	if (bv->bv_status == BIOC_SVREBUILD ||
907 	    bv->bv_status == BIOC_SVBUILDING)
908 		bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) /
909 		    blks;
910 
911 	return (0);
912 }
913 
914 #ifndef SMALL_KERNEL
915 int
916 cac_create_sensors(struct cac_softc *sc)
917 {
918 	struct device *dev;
919 	struct scsibus_softc *ssc = NULL;
920 	struct scsi_link *link;
921 	int i;
922 
923 	TAILQ_FOREACH(dev, &alldevs, dv_list) {
924 		if (dev->dv_parent != &sc->sc_dv)
925 			continue;
926 
927 		/* check if this is the scsibus for the logical disks */
928 		ssc = (struct scsibus_softc *)dev;
929 		if (ssc->adapter_link == &sc->sc_link)
930 			break;
931 		ssc = NULL;
932 	}
933 
934 	if (ssc == NULL)
935 		return (1);
936 
937 	sc->sc_sensors = malloc(sizeof(struct ksensor) * sc->sc_nunits,
938 	    M_DEVBUF, M_NOWAIT | M_ZERO);
939 	if (sc->sc_sensors == NULL)
940 		return (1);
941 
942 	strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
943 	    sizeof(sc->sc_sensordev.xname));
944 
945 	for (i = 0; i < sc->sc_nunits; i++) {
946 		link = scsi_get_link(ssc, i, 0);
947 		if (link == NULL)
948 			goto bad;
949 
950 		dev = link->device_softc;
951 
952 		sc->sc_sensors[i].type = SENSOR_DRIVE;
953 		sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
954 
955 		strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
956 		    sizeof(sc->sc_sensors[i].desc));
957 
958 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
959 	}
960 
961 	if (sensor_task_register(sc, cac_sensor_refresh, 10) == NULL)
962 		goto bad;
963 
964 	sensordev_install(&sc->sc_sensordev);
965 
966 	return (0);
967 
968 bad:
969 	free(sc->sc_sensors, M_DEVBUF);
970 
971 	return (1);
972 }
973 
974 void
975 cac_sensor_refresh(void *arg)
976 {
977 	struct cac_softc *sc = arg;
978 	struct bioc_vol bv;
979 	int i, s;
980 
981 	for (i = 0; i < sc->sc_nunits; i++) {
982 		bzero(&bv, sizeof(bv));
983 		bv.bv_volid = i;
984 		s = splbio();
985 		if (cac_ioctl_vol(sc, &bv)) {
986 			splx(s);
987 			return;
988 		}
989 		splx(s);
990 
991 		switch (bv.bv_status) {
992 		case BIOC_SVOFFLINE:
993 			sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
994 			sc->sc_sensors[i].status = SENSOR_S_CRIT;
995 			break;
996 
997 		case BIOC_SVDEGRADED:
998 			sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
999 			sc->sc_sensors[i].status = SENSOR_S_WARN;
1000 			break;
1001 
1002 		case BIOC_SVSCRUB:
1003 		case BIOC_SVONLINE:
1004 			sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
1005 			sc->sc_sensors[i].status = SENSOR_S_OK;
1006 			break;
1007 
1008 		case BIOC_SVREBUILD:
1009 		case BIOC_SVBUILDING:
1010 			sc->sc_sensors[i].value = SENSOR_DRIVE_REBUILD;
1011 			sc->sc_sensors[i].status = SENSOR_S_OK;
1012 			break;
1013 
1014 		case BIOC_SVINVALID:
1015 			/* FALLTRHOUGH */
1016 		default:
1017 			sc->sc_sensors[i].value = 0; /* unknown */
1018 			sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
1019 		}
1020 	}
1021 }
1022 #endif /* SMALL_KERNEL */
1023 #endif /* NBIO > 0 */
1024