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