xref: /openbsd-src/sys/dev/ic/cac.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$OpenBSD: cac.c,v 1.59 2020/02/15 18:02:00 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 void	cac_copy_internal_data(struct scsi_xfer *xs, void *v, size_t size);
113 
114 struct	cac_ccb *cac_l0_completed(struct cac_softc *);
115 int	cac_l0_fifo_full(struct cac_softc *);
116 void	cac_l0_intr_enable(struct cac_softc *, int);
117 int	cac_l0_intr_pending(struct cac_softc *);
118 void	cac_l0_submit(struct cac_softc *, struct cac_ccb *);
119 
120 #if NBIO > 0
121 int	cac_ioctl(struct device *, u_long, caddr_t);
122 int	cac_ioctl_vol(struct cac_softc *, struct bioc_vol *);
123 
124 #ifndef SMALL_KERNEL
125 int	cac_create_sensors(struct cac_softc *);
126 void	cac_sensor_refresh(void *);
127 #endif
128 #endif /* NBIO > 0 */
129 
130 const
131 struct cac_linkage cac_l0 = {
132 	cac_l0_completed,
133 	cac_l0_fifo_full,
134 	cac_l0_intr_enable,
135 	cac_l0_intr_pending,
136 	cac_l0_submit
137 };
138 
139 /*
140  * Initialise our interface to the controller.
141  */
142 int
143 cac_init(struct cac_softc *sc, int startfw)
144 {
145 	struct scsibus_attach_args saa;
146 	struct cac_controller_info cinfo;
147 	int error, rseg, size, i;
148 	bus_dma_segment_t seg[1];
149 	struct cac_ccb *ccb;
150 
151 	SIMPLEQ_INIT(&sc->sc_ccb_free);
152 	SIMPLEQ_INIT(&sc->sc_ccb_queue);
153 	mtx_init(&sc->sc_ccb_mtx, IPL_BIO);
154 	scsi_iopool_init(&sc->sc_iopool, sc, cac_ccb_alloc, cac_ccb_free);
155 
156         size = sizeof(struct cac_ccb) * CAC_MAX_CCBS;
157 
158 	if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1,
159 	    &rseg, BUS_DMA_NOWAIT | BUS_DMA_ZERO)) != 0) {
160 		printf("%s: unable to allocate CCBs, error = %d\n",
161 		    sc->sc_dv.dv_xname, error);
162 		return (-1);
163 	}
164 
165 	if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size,
166 	    &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) {
167 		printf("%s: unable to map CCBs, error = %d\n",
168 		    sc->sc_dv.dv_xname, error);
169 		return (-1);
170 	}
171 
172 	if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
173 	    BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) {
174 		printf("%s: unable to create CCB DMA map, error = %d\n",
175 		    sc->sc_dv.dv_xname, error);
176 		return (-1);
177 	}
178 
179 	if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs,
180 	    size, NULL, BUS_DMA_NOWAIT)) != 0) {
181 		printf("%s: unable to load CCB DMA map, error = %d\n",
182 		    sc->sc_dv.dv_xname, error);
183 		return (-1);
184 	}
185 
186 	sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr;
187 	ccb = (struct cac_ccb *)sc->sc_ccbs;
188 
189 	for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) {
190 		/* Create the DMA map for this CCB's data */
191 		error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER,
192 		    CAC_SG_SIZE, CAC_MAX_XFER, 0,
193 		    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
194 		    &ccb->ccb_dmamap_xfer);
195 
196 		if (error) {
197 			printf("%s: can't create ccb dmamap (%d)\n",
198 			    sc->sc_dv.dv_xname, error);
199 			break;
200 		}
201 
202 		ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb);
203 		mtx_enter(&sc->sc_ccb_mtx);
204 		SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain);
205 		mtx_leave(&sc->sc_ccb_mtx);
206 	}
207 
208 	/* Start firmware background tasks, if needed. */
209 	if (startfw) {
210 		if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo),
211 		    0, 0, CAC_CCB_DATA_IN, NULL)) {
212 			printf("%s: CAC_CMD_START_FIRMWARE failed\n",
213 			    sc->sc_dv.dv_xname);
214 			return (-1);
215 		}
216 	}
217 
218 	if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0,
219 	    CAC_CCB_DATA_IN, NULL)) {
220 		printf("%s: CAC_CMD_GET_CTRL_INFO failed\n",
221 		    sc->sc_dv.dv_xname);
222 		return (-1);
223 	}
224 
225 	if (!cinfo.num_drvs) {
226 		printf("%s: no volumes defined\n", sc->sc_dv.dv_xname);
227 		return (-1);
228 	}
229 
230 	sc->sc_nunits = cinfo.num_drvs;
231 	sc->sc_dinfos = mallocarray(cinfo.num_drvs,
232 	    sizeof(struct cac_drive_info), M_DEVBUF, M_NOWAIT | M_ZERO);
233 	if (sc->sc_dinfos == NULL) {
234 		printf("%s: cannot allocate memory for drive_info\n",
235 		    sc->sc_dv.dv_xname);
236 		return (-1);
237 	}
238 
239 	sc->sc_link.adapter_softc = sc;
240 	sc->sc_link.adapter = &cac_switch;
241 	sc->sc_link.adapter_target = cinfo.num_drvs;
242 	sc->sc_link.adapter_buswidth = cinfo.num_drvs;
243 	sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits;
244 	if (sc->sc_link.openings < 4 )
245 		sc->sc_link.openings = 4;
246 	sc->sc_link.pool = &sc->sc_iopool;
247 
248 	bzero(&saa, sizeof(saa));
249 	saa.saa_sc_link = &sc->sc_link;
250 
251 	config_found(&sc->sc_dv, &saa, 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_copy_internal_data(xs, v, size)
565 	struct scsi_xfer *xs;
566 	void *v;
567 	size_t size;
568 {
569 	size_t copy_cnt;
570 
571 	if (!xs->datalen)
572 		printf("uio move is not yet supported\n");
573 	else {
574 		copy_cnt = MIN(size, xs->datalen);
575 		memcpy(xs->data, v, copy_cnt);
576 	}
577 }
578 
579 void
580 cac_scsi_cmd(xs)
581 	struct scsi_xfer *xs;
582 {
583 	struct scsi_link *link = xs->sc_link;
584 	struct cac_softc *sc = link->adapter_softc;
585 	struct cac_drive_info *dinfo;
586 	struct scsi_inquiry_data inq;
587 	struct scsi_sense_data sd;
588 	struct scsi_read_cap_data rcd;
589 	u_int8_t target = link->target;
590 	u_int32_t blockno, blockcnt, size;
591 	struct scsi_rw *rw;
592 	struct scsi_rw_big *rwb;
593 	int op, flags, s, error;
594 	const char *p;
595 
596 	if (target >= sc->sc_nunits || link->lun != 0) {
597 		xs->error = XS_DRIVER_STUFFUP;
598 		scsi_done(xs);
599 		return;
600 	}
601 
602 	s = splbio();
603 	xs->error = XS_NOERROR;
604 	dinfo = &sc->sc_dinfos[target];
605 
606 	switch (xs->cmd->opcode) {
607 	case TEST_UNIT_READY:
608 	case START_STOP:
609 #if 0
610 	case VERIFY:
611 #endif
612 		break;
613 
614 	case REQUEST_SENSE:
615 		bzero(&sd, sizeof sd);
616 		sd.error_code = SSD_ERRCODE_CURRENT;
617 		sd.segment = 0;
618 		sd.flags = SKEY_NO_SENSE;
619 		*(u_int32_t*)sd.info = htole32(0);
620 		sd.extra_len = 0;
621 		cac_copy_internal_data(xs, &sd, sizeof sd);
622 		break;
623 
624 	case INQUIRY:
625 		if (cac_get_dinfo(sc, target)) {
626 			xs->error = XS_DRIVER_STUFFUP;
627 			break;
628 		}
629 		bzero(&inq, sizeof inq);
630 		inq.device = T_DIRECT;
631 		inq.dev_qual2 = 0;
632 		inq.version = 2;
633 		inq.response_format = 2;
634 		inq.additional_length = 32;
635 		inq.flags |= SID_CmdQue;
636 		strlcpy(inq.vendor, "Compaq  ", sizeof inq.vendor);
637 		switch (CAC_GET1(dinfo->mirror)) {
638 		case 0: p = "RAID0";	break;
639 		case 1: p = "RAID4";	break;
640 		case 2: p = "RAID1";	break;
641 		case 3: p = "RAID5";	break;
642 		default:p = "<UNK>";	break;
643 		}
644 		snprintf(inq.product, sizeof inq.product, "%s vol  #%02d",
645 		    p, target);
646 		strlcpy(inq.revision, "   ", sizeof inq.revision);
647 		cac_copy_internal_data(xs, &inq, sizeof inq);
648 		break;
649 
650 	case READ_CAPACITY:
651 		if (cac_get_dinfo(sc, target)) {
652 			xs->error = XS_DRIVER_STUFFUP;
653 			break;
654 		}
655 		bzero(&rcd, sizeof rcd);
656 		_lto4b( CAC_GET2(dinfo->ncylinders) * CAC_GET1(dinfo->nheads) *
657 		    CAC_GET1(dinfo->nsectors) - 1, rcd.addr);
658 		_lto4b(CAC_SECTOR_SIZE, rcd.length);
659 		cac_copy_internal_data(xs, &rcd, sizeof rcd);
660 		break;
661 
662 	case PREVENT_ALLOW:
663 		break;
664 
665 	case SYNCHRONIZE_CACHE:
666 		if (cac_flush(sc))
667 			xs->error = XS_DRIVER_STUFFUP;
668 		break;
669 
670 	case READ_COMMAND:
671 	case READ_BIG:
672 	case WRITE_COMMAND:
673 	case WRITE_BIG:
674 
675 		flags = 0;
676 		/* A read or write operation. */
677 		if (xs->cmdlen == 6) {
678 			rw = (struct scsi_rw *)xs->cmd;
679 			blockno = _3btol(rw->addr) &
680 			    (SRW_TOPADDR << 16 | 0xffff);
681 			blockcnt = rw->length ? rw->length : 0x100;
682 		} else {
683 			rwb = (struct scsi_rw_big *)xs->cmd;
684 			blockno = _4btol(rwb->addr);
685 			blockcnt = _2btol(rwb->length);
686 		}
687 		size = CAC_GET2(dinfo->ncylinders) *
688 		    CAC_GET1(dinfo->nheads) * CAC_GET1(dinfo->nsectors);
689 		if (blockno >= size || blockno + blockcnt > size) {
690 			printf("%s: out of bounds %u-%u >= %u\n",
691 			    sc->sc_dv.dv_xname, blockno, blockcnt, size);
692 			xs->error = XS_DRIVER_STUFFUP;
693 			break;
694 		}
695 
696 		switch (xs->cmd->opcode) {
697 		case READ_COMMAND:
698 		case READ_BIG:
699 			op = CAC_CMD_READ;
700 			flags = CAC_CCB_DATA_IN;
701 			break;
702 		case WRITE_COMMAND:
703 		case WRITE_BIG:
704 			op = CAC_CMD_WRITE;
705 			flags = CAC_CCB_DATA_OUT;
706 			break;
707 		}
708 
709 		if ((error = cac_cmd(sc, op, xs->data, blockcnt * DEV_BSIZE,
710 		    target, blockno, flags, xs))) {
711 			splx(s);
712 			if (error == EBUSY)
713 				xs->error = XS_BUSY;
714 			else
715 				xs->error = XS_DRIVER_STUFFUP;
716 			scsi_done(xs);
717 			return;
718 		}
719 
720 		splx(s);
721 		return;
722 
723 	default:
724 		SC_DEBUG(link, SDEV_DB1, ("unsupported scsi command %#x "
725 		    "tgt %d ", xs->cmd->opcode, target));
726 		xs->error = XS_DRIVER_STUFFUP;
727 	}
728 
729 	splx(s);
730 	scsi_done(xs);
731 }
732 
733 /*
734  * Board specific linkage shared between multiple bus types.
735  */
736 
737 int
738 cac_l0_fifo_full(struct cac_softc *sc)
739 {
740 
741 	return (cac_inl(sc, CAC_REG_CMD_FIFO) == 0);
742 }
743 
744 void
745 cac_l0_submit(struct cac_softc *sc, struct cac_ccb *ccb)
746 {
747 #ifdef CAC_DEBUG
748 	printf("submit-%x ", ccb->ccb_paddr);
749 #endif
750 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
751 	    sc->sc_dmamap->dm_mapsize,
752 	    BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD);
753 	cac_outl(sc, CAC_REG_CMD_FIFO, ccb->ccb_paddr);
754 }
755 
756 struct cac_ccb *
757 cac_l0_completed(sc)
758 	struct cac_softc *sc;
759 {
760 	struct cac_ccb *ccb;
761 	paddr_t off, orig_off;
762 
763 	if (!(off = cac_inl(sc, CAC_REG_DONE_FIFO)))
764 		return NULL;
765 #ifdef CAC_DEBUG
766 	printf("compl-%x ", off);
767 #endif
768 	orig_off = off;
769 
770 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, 0,
771 	    sc->sc_dmamap->dm_mapsize,
772 	    BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD);
773 
774 	off = (off & ~3) - sc->sc_ccbs_paddr;
775 	ccb = (struct cac_ccb *)(sc->sc_ccbs + off);
776 
777 	if (orig_off & 3 && ccb->ccb_req.error == 0)
778 		ccb->ccb_req.error = CAC_RET_CMD_INVALID;
779 
780 	return (ccb);
781 }
782 
783 int
784 cac_l0_intr_pending(struct cac_softc *sc)
785 {
786 
787 	return (cac_inl(sc, CAC_REG_INTR_PENDING));
788 }
789 
790 void
791 cac_l0_intr_enable(struct cac_softc *sc, int state)
792 {
793 
794 	cac_outl(sc, CAC_REG_INTR_MASK,
795 	    state ? CAC_INTR_ENABLE : CAC_INTR_DISABLE);
796 }
797 
798 #if NBIO > 0
799 const int cac_level[] = { 0, 4, 1, 5, 51, 7 };
800 const int cac_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
801     BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
802     BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
803     BIOC_SVOFFLINE, BIOC_SVBUILDING };
804 
805 int
806 cac_ioctl(struct device *dev, u_long cmd, caddr_t addr)
807 {
808 	struct cac_softc *sc = (struct cac_softc *)dev;
809 	struct bioc_inq *bi;
810 	struct bioc_disk *bd;
811 	cac_lock_t lock;
812 	int error = 0;
813 
814 	lock = CAC_LOCK(sc);
815 	switch (cmd) {
816 	case BIOCINQ:
817 		bi = (struct bioc_inq *)addr;
818 		strlcpy(bi->bi_dev, sc->sc_dv.dv_xname, sizeof(bi->bi_dev));
819 		bi->bi_novol = sc->sc_nunits;
820 		bi->bi_nodisk = 0;
821 		break;
822 
823 	case BIOCVOL:
824 		error = cac_ioctl_vol(sc, (struct bioc_vol *)addr);
825 		break;
826 
827 	case BIOCDISK:
828 		bd = (struct bioc_disk *)addr;
829 		if (bd->bd_volid > sc->sc_nunits) {
830 			error = EINVAL;
831 			break;
832 		}
833 		/* No disk information yet */
834 		break;
835 
836 	case BIOCBLINK:
837 	case BIOCALARM:
838 	case BIOCSETSTATE:
839 	default:
840 		error = ENOTTY;
841 	}
842 	CAC_UNLOCK(sc, lock);
843 
844 	return (error);
845 }
846 
847 int
848 cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv)
849 {
850 	struct cac_drive_info dinfo;
851 	struct cac_drive_status dstatus;
852 	u_int32_t blks;
853 
854 	if (bv->bv_volid > sc->sc_nunits)
855 		return (EINVAL);
856 	if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo),
857 	    bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
858 		return (EIO);
859 	if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus),
860 	    bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL))
861 		return (EIO);
862 	bv->bv_status = BIOC_SVINVALID;
863 	blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) *
864 	    CAC_GET1(dinfo.nsectors);
865 	bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize);
866 	bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)];	/*XXX limit check */
867 	bv->bv_nodisk = 0;		/* XXX */
868 	bv->bv_status = 0;		/* XXX */
869 	bv->bv_percent = -1;
870 	bv->bv_seconds = 0;
871 	if (dstatus.stat < nitems(cac_stat))
872 		bv->bv_status = cac_stat[dstatus.stat];
873 	if (bv->bv_status == BIOC_SVREBUILD ||
874 	    bv->bv_status == BIOC_SVBUILDING)
875 		bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) /
876 		    blks;
877 
878 	return (0);
879 }
880 
881 #ifndef SMALL_KERNEL
882 int
883 cac_create_sensors(struct cac_softc *sc)
884 {
885 	struct device *dev;
886 	struct scsibus_softc *ssc = NULL;
887 	struct scsi_link *link;
888 	int i;
889 
890 	TAILQ_FOREACH(dev, &alldevs, dv_list) {
891 		if (dev->dv_parent != &sc->sc_dv)
892 			continue;
893 
894 		/* check if this is the scsibus for the logical disks */
895 		ssc = (struct scsibus_softc *)dev;
896 		if (ssc->adapter_link == &sc->sc_link)
897 			break;
898 		ssc = NULL;
899 	}
900 
901 	if (ssc == NULL)
902 		return (1);
903 
904 	sc->sc_sensors = mallocarray(sc->sc_nunits,
905 	    sizeof(struct ksensor), M_DEVBUF, M_NOWAIT | M_ZERO);
906 	if (sc->sc_sensors == NULL)
907 		return (1);
908 
909 	strlcpy(sc->sc_sensordev.xname, sc->sc_dv.dv_xname,
910 	    sizeof(sc->sc_sensordev.xname));
911 
912 	for (i = 0; i < sc->sc_nunits; i++) {
913 		link = scsi_get_link(ssc, i, 0);
914 		if (link == NULL)
915 			goto bad;
916 
917 		dev = link->device_softc;
918 
919 		sc->sc_sensors[i].type = SENSOR_DRIVE;
920 		sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
921 
922 		strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
923 		    sizeof(sc->sc_sensors[i].desc));
924 
925 		sensor_attach(&sc->sc_sensordev, &sc->sc_sensors[i]);
926 	}
927 
928 	if (sensor_task_register(sc, cac_sensor_refresh, 10) == NULL)
929 		goto bad;
930 
931 	sensordev_install(&sc->sc_sensordev);
932 
933 	return (0);
934 
935 bad:
936 	free(sc->sc_sensors, M_DEVBUF,
937 	    sc->sc_nunits * sizeof(struct ksensor));
938 
939 	return (1);
940 }
941 
942 void
943 cac_sensor_refresh(void *arg)
944 {
945 	struct cac_softc *sc = arg;
946 	struct bioc_vol bv;
947 	int i, s;
948 
949 	for (i = 0; i < sc->sc_nunits; i++) {
950 		bzero(&bv, sizeof(bv));
951 		bv.bv_volid = i;
952 		s = splbio();
953 		if (cac_ioctl_vol(sc, &bv)) {
954 			splx(s);
955 			return;
956 		}
957 		splx(s);
958 
959 		switch (bv.bv_status) {
960 		case BIOC_SVOFFLINE:
961 			sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
962 			sc->sc_sensors[i].status = SENSOR_S_CRIT;
963 			break;
964 
965 		case BIOC_SVDEGRADED:
966 			sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
967 			sc->sc_sensors[i].status = SENSOR_S_WARN;
968 			break;
969 
970 		case BIOC_SVSCRUB:
971 		case BIOC_SVONLINE:
972 			sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
973 			sc->sc_sensors[i].status = SENSOR_S_OK;
974 			break;
975 
976 		case BIOC_SVREBUILD:
977 		case BIOC_SVBUILDING:
978 			sc->sc_sensors[i].value = SENSOR_DRIVE_REBUILD;
979 			sc->sc_sensors[i].status = SENSOR_S_OK;
980 			break;
981 
982 		case BIOC_SVINVALID:
983 			/* FALLTRHOUGH */
984 		default:
985 			sc->sc_sensors[i].value = 0; /* unknown */
986 			sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
987 		}
988 	}
989 }
990 #endif /* SMALL_KERNEL */
991 #endif /* NBIO > 0 */
992