xref: /openbsd/sys/dev/ic/cac.c (revision 510d2225)
1 /*	$OpenBSD: cac.c,v 1.77 2023/11/28 09:29:20 jsg 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 const 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(struct cac_softc *sc)
274 {
275 	u_int8_t buf[512];
276 
277 	memset(buf, 0, sizeof(buf));
278 	buf[0] = 1;
279 	return cac_cmd(sc, CAC_CMD_FLUSH_CACHE, buf, sizeof(buf), 0, 0,
280 	    CAC_CCB_DATA_OUT, NULL);
281 }
282 
283 /*
284  * Handle an interrupt from the controller: process finished CCBs and
285  * dequeue any waiting CCBs.
286  */
287 int
288 cac_intr(void *v)
289 {
290 	struct cac_softc *sc = v;
291 	struct cac_ccb *ccb;
292 	int istat, ret = 0;
293 
294 	if (!(istat = (*sc->sc_cl->cl_intr_pending)(sc)))
295 		return 0;
296 
297 	if (istat & CAC_INTR_FIFO_NEMPTY)
298 		while ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL) {
299 			ret = 1;
300 			cac_ccb_done(sc, ccb);
301 		}
302 	cac_ccb_start(sc, NULL);
303 
304 	return (ret);
305 }
306 
307 /*
308  * Execute a [polled] command.
309  */
310 int
311 cac_cmd(struct cac_softc *sc, int command, void *data, int datasize,
312 	int drive, int blkno, int flags, struct scsi_xfer *xs)
313 {
314 	struct cac_ccb *ccb;
315 	struct cac_sgb *sgb;
316 	int i, rv, size, nsegs;
317 
318 #ifdef CAC_DEBUG
319 	printf("cac_cmd op=%x drv=%d blk=%d data=%p[%x] fl=%x xs=%p ",
320 	    command, drive, blkno, data, datasize, flags, xs);
321 #endif
322 
323 	if (xs) {
324 		ccb = xs->io;
325 		/*
326 		 * The xs may have been restarted by the scsi layer, so
327 		 * ensure the ccb starts in the proper state.
328 		 */
329 		ccb->ccb_flags = 0;
330 	} else {
331 		/* Internal command. Need to get our own ccb. */
332 		ccb = scsi_io_get(&sc->sc_iopool, SCSI_POLL | SCSI_NOSLEEP);
333 		if (ccb == NULL)
334 			return (EBUSY);
335 	}
336 
337 	if ((flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
338 		bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap_xfer,
339 		    (void *)data, datasize, NULL, BUS_DMA_NOWAIT);
340 
341 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
342 		    ccb->ccb_dmamap_xfer->dm_mapsize,
343 		    (flags & CAC_CCB_DATA_IN) != 0 ? BUS_DMASYNC_PREREAD :
344 		    BUS_DMASYNC_PREWRITE);
345 
346 		sgb = ccb->ccb_seg;
347 		nsegs = ccb->ccb_dmamap_xfer->dm_nsegs;
348 		if (nsegs > CAC_SG_SIZE)
349 			panic("cac_cmd: nsegs botch");
350 
351 		size = 0;
352 		for (i = 0; i < nsegs; i++, sgb++) {
353 			size += ccb->ccb_dmamap_xfer->dm_segs[i].ds_len;
354 			sgb->length =
355 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_len);
356 			sgb->addr =
357 			    htole32(ccb->ccb_dmamap_xfer->dm_segs[i].ds_addr);
358 		}
359 	} else {
360 		size = datasize;
361 		nsegs = 0;
362 	}
363 
364 	ccb->ccb_hdr.drive = drive;
365 	ccb->ccb_hdr.priority = 0;
366 	ccb->ccb_hdr.size = htole16((sizeof(struct cac_req) +
367 	    sizeof(struct cac_sgb) * CAC_SG_SIZE) >> 2);
368 
369 	ccb->ccb_req.next = 0;
370 	ccb->ccb_req.command = command;
371 	ccb->ccb_req.error = 0;
372 	ccb->ccb_req.blkno = htole32(blkno);
373 	ccb->ccb_req.bcount = htole16(howmany(size, DEV_BSIZE));
374 	ccb->ccb_req.sgcount = nsegs;
375 	ccb->ccb_req.reserved = 0;
376 
377 	ccb->ccb_flags = flags;
378 	ccb->ccb_datasize = size;
379 	ccb->ccb_xs = xs;
380 
381 	if (!xs || xs->flags & SCSI_POLL) {
382 		/* Synchronous commands mustn't wait. */
383 		mtx_enter(&sc->sc_ccb_mtx);
384 		if ((*sc->sc_cl->cl_fifo_full)(sc)) {
385 			mtx_leave(&sc->sc_ccb_mtx);
386 			rv = EBUSY;
387 		} else {
388 			mtx_leave(&sc->sc_ccb_mtx);
389 			ccb->ccb_flags |= CAC_CCB_ACTIVE;
390 			(*sc->sc_cl->cl_submit)(sc, ccb);
391 			rv = cac_ccb_poll(sc, ccb, 2000);
392 		}
393 	} else
394 		rv = cac_ccb_start(sc, ccb);
395 
396 	if (xs == NULL)
397 		scsi_io_put(&sc->sc_iopool, ccb);
398 
399 	return (rv);
400 }
401 
402 /*
403  * Wait for the specified CCB to complete.  Must be called at splbio.
404  */
405 int
406 cac_ccb_poll(struct cac_softc *sc, struct cac_ccb *wantccb, int timo)
407 {
408 	struct cac_ccb *ccb;
409 	int t;
410 
411 	t = timo * 100;
412 	do {
413 		for (; t--; DELAY(10))
414 			if ((ccb = (*sc->sc_cl->cl_completed)(sc)) != NULL)
415 				break;
416 		if (t < 0) {
417 			printf("%s: timeout\n", sc->sc_dv.dv_xname);
418 			return (EBUSY);
419 		}
420 		cac_ccb_done(sc, ccb);
421 	} while (ccb != wantccb);
422 
423 	return (0);
424 }
425 
426 /*
427  * Enqueue the specified command (if any) and attempt to start all enqueued
428  * commands.
429  */
430 int
431 cac_ccb_start(struct cac_softc *sc, struct cac_ccb *ccb)
432 {
433 	if (ccb != NULL) {
434 		mtx_enter(&sc->sc_ccb_mtx);
435 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_queue, ccb, ccb_chain);
436 		mtx_leave(&sc->sc_ccb_mtx);
437 	}
438 
439 	while (1) {
440 		mtx_enter(&sc->sc_ccb_mtx);
441 		if (SIMPLEQ_EMPTY(&sc->sc_ccb_queue) ||
442 		    (*sc->sc_cl->cl_fifo_full)(sc)) {
443 			mtx_leave(&sc->sc_ccb_mtx);
444 			break;
445 		}
446 		ccb = SIMPLEQ_FIRST(&sc->sc_ccb_queue);
447 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_queue, ccb_chain);
448 		mtx_leave(&sc->sc_ccb_mtx);
449 
450 		ccb->ccb_flags |= CAC_CCB_ACTIVE;
451 		(*sc->sc_cl->cl_submit)(sc, ccb);
452 	}
453 
454 	return (0);
455 }
456 
457 /*
458  * Process a finished CCB.
459  */
460 void
461 cac_ccb_done(struct cac_softc *sc, struct cac_ccb *ccb)
462 {
463 	struct scsi_xfer *xs = ccb->ccb_xs;
464 	int error = 0;
465 
466 	if ((ccb->ccb_flags & CAC_CCB_ACTIVE) == 0) {
467 		printf("%s: CCB not active, xs=%p\n", sc->sc_dv.dv_xname, xs);
468 		if (xs) {
469 			xs->error = XS_DRIVER_STUFFUP;
470 			scsi_done(xs);
471 		}
472 		return;
473 	}
474 
475 	if ((ccb->ccb_flags & (CAC_CCB_DATA_IN | CAC_CCB_DATA_OUT)) != 0) {
476 		bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap_xfer, 0,
477 		    ccb->ccb_dmamap_xfer->dm_mapsize,
478 		    ccb->ccb_flags & CAC_CCB_DATA_IN ?
479 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
480 		bus_dmamap_unload(sc->sc_dmat, ccb->ccb_dmamap_xfer);
481 	}
482 
483 	if ((ccb->ccb_req.error & CAC_RET_SOFT_ERROR) != 0)
484 		printf("%s: soft error; corrected\n", sc->sc_dv.dv_xname);
485 	if ((ccb->ccb_req.error & CAC_RET_HARD_ERROR) != 0) {
486 		error = 1;
487 		printf("%s: hard error\n", sc->sc_dv.dv_xname);
488 	}
489 	if ((ccb->ccb_req.error & CAC_RET_CMD_REJECTED) != 0) {
490 		error = 1;
491 		printf("%s: invalid request\n", sc->sc_dv.dv_xname);
492 	}
493 
494 	if (xs) {
495 		if (error)
496 			xs->error = XS_DRIVER_STUFFUP;
497 		else
498 			xs->resid = 0;
499 
500 		scsi_done(xs);
501 	}
502 }
503 
504 /*
505  * Allocate a CCB.
506  */
507 void *
508 cac_ccb_alloc(void *xsc)
509 {
510 	struct cac_softc *sc = xsc;
511 	struct cac_ccb *ccb = NULL;
512 
513 	mtx_enter(&sc->sc_ccb_mtx);
514 	if (SIMPLEQ_EMPTY(&sc->sc_ccb_free)) {
515 #ifdef CAC_DEBUG
516 		printf("%s: unable to alloc CCB\n", sc->sc_dv.dv_xname);
517 #endif
518 	} else {
519 		ccb = SIMPLEQ_FIRST(&sc->sc_ccb_free);
520 		SIMPLEQ_REMOVE_HEAD(&sc->sc_ccb_free, ccb_chain);
521 	}
522 	mtx_leave(&sc->sc_ccb_mtx);
523 
524 	return (ccb);
525 }
526 
527 /*
528  * Put a CCB onto the freelist.
529  */
530 void
531 cac_ccb_free(void *xsc, void *xccb)
532 {
533 	struct cac_softc *sc = xsc;
534 	struct cac_ccb *ccb = xccb;
535 
536 	ccb->ccb_flags = 0;
537 
538 	mtx_enter(&sc->sc_ccb_mtx);
539 	SIMPLEQ_INSERT_HEAD(&sc->sc_ccb_free, ccb, ccb_chain);
540 	mtx_leave(&sc->sc_ccb_mtx);
541 }
542 
543 int
544 cac_get_dinfo(struct cac_softc *sc, int target)
545 {
546 	if (sc->sc_dinfos[target].ncylinders)
547 		return (0);
548 
549 	if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &sc->sc_dinfos[target],
550 	    sizeof(*sc->sc_dinfos), target, 0, CAC_CCB_DATA_IN, NULL)) {
551 		printf("%s: CMD_GET_LOG_DRV_INFO failed\n",
552 		    sc->sc_dv.dv_xname);
553 		return (-1);
554 	}
555 
556 	return (0);
557 }
558 
559 void
560 cac_scsi_cmd(struct scsi_xfer *xs)
561 {
562 	struct scsi_link *link = xs->sc_link;
563 	struct cac_softc *sc = link->bus->sb_adapter_softc;
564 	struct cac_drive_info *dinfo;
565 	struct scsi_inquiry_data inq;
566 	struct scsi_sense_data sd;
567 	struct scsi_read_cap_data rcd;
568 	u_int8_t target = link->target;
569 	u_int32_t blockno, blockcnt, size;
570 	struct scsi_rw *rw;
571 	struct scsi_rw_10 *rw10;
572 	int op, flags, s, error;
573 	const char *p;
574 
575 	if (target >= sc->sc_nunits || link->lun != 0) {
576 		xs->error = XS_DRIVER_STUFFUP;
577 		scsi_done(xs);
578 		return;
579 	}
580 
581 	s = splbio();
582 	xs->error = XS_NOERROR;
583 	dinfo = &sc->sc_dinfos[target];
584 
585 	switch (xs->cmd.opcode) {
586 	case TEST_UNIT_READY:
587 	case START_STOP:
588 #if 0
589 	case VERIFY:
590 #endif
591 		break;
592 
593 	case REQUEST_SENSE:
594 		bzero(&sd, sizeof sd);
595 		sd.error_code = SSD_ERRCODE_CURRENT;
596 		sd.segment = 0;
597 		sd.flags = SKEY_NO_SENSE;
598 		*(u_int32_t*)sd.info = htole32(0);
599 		sd.extra_len = 0;
600 		scsi_copy_internal_data(xs, &sd, sizeof(sd));
601 		break;
602 
603 	case INQUIRY:
604 		if (cac_get_dinfo(sc, target)) {
605 			xs->error = XS_DRIVER_STUFFUP;
606 			break;
607 		}
608 		bzero(&inq, sizeof inq);
609 		inq.device = T_DIRECT;
610 		inq.dev_qual2 = 0;
611 		inq.version = SCSI_REV_2;
612 		inq.response_format = SID_SCSI2_RESPONSE;
613 		inq.additional_length = SID_SCSI2_ALEN;
614 		inq.flags |= SID_CmdQue;
615 		strlcpy(inq.vendor, "Compaq  ", sizeof inq.vendor);
616 		switch (CAC_GET1(dinfo->mirror)) {
617 		case 0: p = "RAID0";	break;
618 		case 1: p = "RAID4";	break;
619 		case 2: p = "RAID1";	break;
620 		case 3: p = "RAID5";	break;
621 		default:p = "<UNK>";	break;
622 		}
623 		snprintf(inq.product, sizeof inq.product, "%s vol  #%02d",
624 		    p, target);
625 		strlcpy(inq.revision, "   ", sizeof inq.revision);
626 		scsi_copy_internal_data(xs, &inq, sizeof(inq));
627 		break;
628 
629 	case READ_CAPACITY:
630 		if (cac_get_dinfo(sc, target)) {
631 			xs->error = XS_DRIVER_STUFFUP;
632 			break;
633 		}
634 		bzero(&rcd, sizeof rcd);
635 		_lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
636 		    CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
637 		_lto4b(CAC_SECTOR_SIZE, rcd.length);
638 		scsi_copy_internal_data(xs, &rcd, sizeof(rcd));
639 		break;
640 
641 	case PREVENT_ALLOW:
642 		break;
643 
644 	case SYNCHRONIZE_CACHE:
645 		if (cac_flush(sc))
646 			xs->error = XS_DRIVER_STUFFUP;
647 		break;
648 
649 	case READ_COMMAND:
650 	case READ_10:
651 	case WRITE_COMMAND:
652 	case WRITE_10:
653 
654 		flags = 0;
655 		/* A read or write operation. */
656 		if (xs->cmdlen == 6) {
657 			rw = (struct scsi_rw *)&xs->cmd;
658 			blockno = _3btol(rw->addr) &
659 			    (SRW_TOPADDR << 16 | 0xffff);
660 			blockcnt = rw->length ? rw->length : 0x100;
661 		} else {
662 			rw10 = (struct scsi_rw_10 *)&xs->cmd;
663 			blockno = _4btol(rw10->addr);
664 			blockcnt = _2btol(rw10->length);
665 		}
666 		size = CAC_GET2(dinfo->ncylinders) *
667 		    CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
668 		if (blockno >= size || blockno + blockcnt > size) {
669 			printf("%s: out of bounds %u-%u >= %u\n",
670 			    sc->sc_dv.dv_xname, blockno, blockcnt, size);
671 			xs->error = XS_DRIVER_STUFFUP;
672 			break;
673 		}
674 
675 		switch (xs->cmd.opcode) {
676 		case READ_COMMAND:
677 		case READ_10:
678 			op = CAC_CMD_READ;
679 			flags = CAC_CCB_DATA_IN;
680 			break;
681 		case WRITE_COMMAND:
682 		case WRITE_10:
683 			op = CAC_CMD_WRITE;
684 			flags = CAC_CCB_DATA_OUT;
685 			break;
686 		}
687 
688 		if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
689 		    target, blockno, flags, xs))) {
690 			splx(s);
691 			if (error == EBUSY)
692 				xs->error = XS_BUSY;
693 			else
694 				xs->error = XS_DRIVER_STUFFUP;
695 			scsi_done(xs);
696 			return;
697 		}
698 
699 		splx(s);
700 		return;
701 
702 	default:
703 #ifdef CAC_DEBUG
704 		printf("unsupported scsi command %#x tgt %d ", xs->cmd.opcode, target);
705 #endif
706 		xs->error = XS_DRIVER_STUFFUP;
707 	}
708 
709 	splx(s);
710 	scsi_done(xs);
711 }
712 
713 /*
714  * Board specific linkage shared between multiple bus types.
715  */
716 
717 int
718 cac_l0_fifo_full(struct cac_softc *sc)
719 {
720 
721 	return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
722 }
723 
724 void
725 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
726 {
727 #ifdef CAC_DEBUG
728 	printf("submit-%lx ", ccb->ccb_paddr);
729 #endif
730 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
731 	    sc->sc_dmamap->dm_mapsize,
732 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
733 	cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
734 }
735 
736 struct cac_ccb *
737 cac_l0_completed(struct cac_softc *sc)
738 {
739 	struct cac_ccb *ccb;
740 	paddr_t off, orig_off;
741 
742 	if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
743 		return NULL;
744 #ifdef CAC_DEBUG
745 	printf("compl-%lx ", off);
746 #endif
747 	orig_off = off;
748 
749 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
750 	    sc->sc_dmamap->dm_mapsize,
751 	    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
752 
753 	off = (off & ~3) - sc->sc_ccbs_paddr;
754 	ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
755 
756 	if (orig_off & 3 && ccb->ccb_req.error == 0)
757 		ccb->ccb_req.error = CAC_RET_CMD_INVALID;
758 
759 	return (ccb);
760 }
761 
762 int
763 cac_l0_intr_pending(struct cac_softc *sc)
764 {
765 
766 	return (cac_inl(sc, CAC_REG_INTR_PENDING));
767 }
768 
769 void
770 cac_l0_intr_enable(struct cac_softc *sc, int state)
771 {
772 
773 	cac_outl(sc, CAC_REG_INTR_MASK,
774 	    state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
775 }
776 
777 #if NBIO > 0
778 const int cac_level[] = { 0, 4, 1, 5, 51, 7 };
779 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
780     BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
781     BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
782     BIOC_SVOFFLINE, BIOC_SVBUILDING };
783 
784 int
785 cac_ioctl(struct device *dev, u_long cmd, caddr_t addr)
786 {
787 	struct cac_softc *sc = (struct cac_softc *)dev;
788 	struct bioc_inq *bi;
789 	struct bioc_disk *bd;
790 	cac_lock_t lock;
791 	int error = 0;
792 
793 	lock = CAC_LOCK(sc);
794 	switch (cmd) {
795 	case BIOCINQ:
796 		bi = (struct bioc_inq *)addr;
797 		strlcpy(bi->bi_dev, sc->sc_dv.dv_xname, sizeof(bi->bi_dev));
798 		bi->bi_novol = sc->sc_nunits;
799 		bi->bi_nodisk = 0;
800 		break;
801 
802 	case BIOCVOL:
803 		error = cac_ioctl_vol(sc, (struct bioc_vol *)addr);
804 		break;
805 
806 	case BIOCDISK:
807 		bd = (struct bioc_disk *)addr;
808 		if (bd->bd_volid > sc->sc_nunits) {
809 			error = EINVAL;
810 			break;
811 		}
812 		/* No disk information yet */
813 		break;
814 
815 	case BIOCBLINK:
816 	case BIOCALARM:
817 	case BIOCSETSTATE:
818 	default:
819 		error = ENOTTY;
820 	}
821 	CAC_UNLOCK(sc, lock);
822 
823 	return (error);
824 }
825 
826 int
827 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv)
828 {
829 	struct cac_drive_info dinfo;
830 	struct cac_drive_status dstatus;
831 	u_int32_t blks;
832 
833 	if (bv->bv_volid > sc->sc_nunits)
834 		return (EINVAL);
835 	if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo),
836 	    bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
837 		return (EIO);
838 	if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus),
839 	    bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
840 		return (EIO);
841 	bv->bv_status = BIOC_SVINVALID;
842 	blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) *
843 	    CAC_GET1(dinfo.nsectors);
844 	bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize);
845 	bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)];	/*XXX limit check */
846 	bv->bv_nodisk = 0;		/* XXX */
847 	bv->bv_status = 0;		/* XXX */
848 	bv->bv_percent = -1;
849 	bv->bv_seconds = 0;
850 	if (dstatus.stat < nitems(cac_stat))
851 		bv->bv_status = cac_stat[dstatus.stat];
852 	if (bv->bv_status == BIOC_SVREBUILD ||
853 	    bv->bv_status == BIOC_SVBUILDING)
854 		bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) /
855 		    blks;
856 
857 	return (0);
858 }
859 
860 #ifndef SMALL_KERNEL
861 int
862 cac_create_sensors(struct cac_softc *sc)
863 {
864 	struct device *dev;
865 	struct scsibus_softc *ssc = NULL;
866 	struct scsi_link *link;
867 	int i;
868 
869 	TAILQ_FOREACH(dev, &alldevs, dv_list) {
870 		if (dev->dv_parent != &sc->sc_dv)
871 			continue;
872 
873 		/* check if this is the scsibus for the logical disks */
874 		ssc = (struct scsibus_softc *)dev;
875 		if (ssc == sc->sc_scsibus)
876 			break;
877 		ssc = NULL;
878 	}
879 
880 	if (ssc == NULL)
881 		return (1);
882 
883 	sc->sc_sensors = mallocarray(sc->sc_nunits,
884 	    sizeof(struct ksensor), M_DEVBUF, M_NOWAIT | M_ZERO);
885 	if (sc->sc_sensors == NULL)
886 		return (1);
887 
888 	strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
889 	    sizeof(sc->sc_sensordev.xname));
890 
891 	for (i = 0; i < sc->sc_nunits; i++) {
892 		link = scsi_get_link(ssc, i, 0);
893 		if (link == NULL)
894 			goto bad;
895 
896 		dev = link->device_softc;
897 
898 		sc->sc_sensors[i].type = SENSOR_DRIVE;
899 		sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
900 
901 		strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
902 		    sizeof(sc->sc_sensors[i].desc));
903 
904 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
905 	}
906 
907 	if (sensor_task_register(sc, cac_sensor_refresh, 10) == NULL)
908 		goto bad;
909 
910 	sensordev_install(&sc->sc_sensordev);
911 
912 	return (0);
913 
914 bad:
915 	free(sc->sc_sensors, M_DEVBUF,
916 	    sc->sc_nunits * sizeof(struct ksensor));
917 
918 	return (1);
919 }
920 
921 void
922 cac_sensor_refresh(void *arg)
923 {
924 	struct cac_softc *sc = arg;
925 	struct bioc_vol bv;
926 	int i, s;
927 
928 	for (i = 0; i < sc->sc_nunits; i++) {
929 		bzero(&bv, sizeof(bv));
930 		bv.bv_volid = i;
931 		s = splbio();
932 		if (cac_ioctl_vol(sc, &bv)) {
933 			splx(s);
934 			return;
935 		}
936 		splx(s);
937 
938 		switch (bv.bv_status) {
939 		case BIOC_SVOFFLINE:
940 			sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
941 			sc->sc_sensors[i].status = SENSOR_S_CRIT;
942 			break;
943 
944 		case BIOC_SVDEGRADED:
945 			sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
946 			sc->sc_sensors[i].status = SENSOR_S_WARN;
947 			break;
948 
949 		case BIOC_SVSCRUB:
950 		case BIOC_SVONLINE:
951 			sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
952 			sc->sc_sensors[i].status = SENSOR_S_OK;
953 			break;
954 
955 		case BIOC_SVREBUILD:
956 		case BIOC_SVBUILDING:
957 			sc->sc_sensors[i].value = SENSOR_DRIVE_REBUILD;
958 			sc->sc_sensors[i].status = SENSOR_S_OK;
959 			break;
960 
961 		case BIOC_SVINVALID:
962 			/* FALLTHROUGH */
963 		default:
964 			sc->sc_sensors[i].value = 0; /* unknown */
965 			sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
966 		}
967 	}
968 }
969 #endif /* SMALL_KERNEL */
970 #endif /* NBIO > 0 */
971