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