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