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