xref: /openbsd-src/sys/dev/ic/ciss.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: ciss.c,v 1.33 2009/02/16 21:19:06 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 2005,2006 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
16  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include "bio.h"
21 
22 /* #define CISS_DEBUG */
23 
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/buf.h>
27 #include <sys/ioctl.h>
28 #include <sys/device.h>
29 #include <sys/kernel.h>
30 #include <sys/malloc.h>
31 #include <sys/proc.h>
32 #include <sys/kthread.h>
33 
34 #include <machine/bus.h>
35 
36 #include <scsi/scsi_all.h>
37 #include <scsi/scsi_disk.h>
38 #include <scsi/scsiconf.h>
39 
40 #include <dev/ic/cissreg.h>
41 #include <dev/ic/cissvar.h>
42 
43 #if NBIO > 0
44 #include <dev/biovar.h>
45 #endif
46 #include <sys/sensors.h>
47 
48 #ifdef CISS_DEBUG
49 #define	CISS_DPRINTF(m,a)	if (ciss_debug & (m)) printf a
50 #define	CISS_D_CMD	0x0001
51 #define	CISS_D_INTR	0x0002
52 #define	CISS_D_MISC	0x0004
53 #define	CISS_D_DMA	0x0008
54 #define	CISS_D_IOCTL	0x0010
55 #define	CISS_D_ERR	0x0020
56 int ciss_debug = 0
57 /*	| CISS_D_CMD */
58 /*	| CISS_D_INTR */
59 /*	| CISS_D_MISC */
60 /*	| CISS_D_DMA */
61 /*	| CISS_D_IOCTL */
62 /*	| CISS_D_ERR */
63 	;
64 #else
65 #define	CISS_DPRINTF(m,a)	/* m, a */
66 #endif
67 
68 struct cfdriver ciss_cd = {
69 	NULL, "ciss", DV_DULL
70 };
71 
72 int	ciss_scsi_cmd(struct scsi_xfer *xs);
73 int	ciss_scsi_ioctl(struct scsi_link *link, u_long cmd,
74     caddr_t addr, int flag, struct proc *p);
75 void	cissminphys(struct buf *bp, struct scsi_link *sl);
76 
77 struct scsi_adapter ciss_switch = {
78 	ciss_scsi_cmd, cissminphys, NULL, NULL, ciss_scsi_ioctl
79 };
80 
81 struct scsi_device ciss_dev = {
82 	NULL, NULL, NULL, NULL
83 };
84 
85 int	ciss_scsi_raw_cmd(struct scsi_xfer *xs);
86 
87 struct scsi_adapter ciss_raw_switch = {
88 	ciss_scsi_raw_cmd, cissminphys, NULL, NULL,
89 };
90 
91 struct scsi_device ciss_raw_dev = {
92 	NULL, NULL, NULL, NULL
93 };
94 
95 #if NBIO > 0
96 int	ciss_ioctl(struct device *, u_long, caddr_t);
97 #endif
98 int	ciss_sync(struct ciss_softc *sc);
99 void	ciss_heartbeat(void *v);
100 void	ciss_shutdown(void *v);
101 void	ciss_kthread(void *v);
102 #ifndef SMALL_KERNEL
103 void	ciss_sensors(void *);
104 #endif
105 
106 struct ciss_ccb *ciss_get_ccb(struct ciss_softc *sc);
107 void	ciss_put_ccb(struct ciss_ccb *ccb);
108 int	ciss_cmd(struct ciss_ccb *ccb, int flags, int wait);
109 int	ciss_done(struct ciss_ccb *ccb);
110 int	ciss_error(struct ciss_ccb *ccb);
111 
112 struct ciss_ld *ciss_pdscan(struct ciss_softc *sc, int ld);
113 int	ciss_inq(struct ciss_softc *sc, struct ciss_inquiry *inq);
114 int	ciss_ldmap(struct ciss_softc *sc);
115 int	ciss_ldid(struct ciss_softc *, int, struct ciss_ldid *);
116 int	ciss_ldstat(struct ciss_softc *, int, struct ciss_ldstat *);
117 int	ciss_pdid(struct ciss_softc *, u_int8_t, struct ciss_pdid *, int);
118 int	ciss_blink(struct ciss_softc *, int, int, int, struct ciss_blink *);
119 
120 struct ciss_ccb *
121 ciss_get_ccb(struct ciss_softc *sc)
122 {
123 	struct ciss_ccb *ccb;
124 
125 	if ((ccb = TAILQ_LAST(&sc->sc_free_ccb, ciss_queue_head))) {
126 		TAILQ_REMOVE(&sc->sc_free_ccb, ccb, ccb_link);
127 		ccb->ccb_state = CISS_CCB_READY;
128 	}
129 	return ccb;
130 }
131 
132 void
133 ciss_put_ccb(struct ciss_ccb *ccb)
134 {
135 	struct ciss_softc *sc = ccb->ccb_sc;
136 
137 	ccb->ccb_state = CISS_CCB_FREE;
138 	TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link);
139 }
140 
141 int
142 ciss_attach(struct ciss_softc *sc)
143 {
144 	struct scsibus_attach_args saa;
145 	struct scsibus_softc *scsibus;
146 	struct ciss_ccb *ccb;
147 	struct ciss_cmd *cmd;
148 	struct ciss_inquiry *inq;
149 	bus_dma_segment_t seg[1];
150 	int error, i, total, rseg, maxfer;
151 	ciss_lock_t lock;
152 	paddr_t pa;
153 
154 	bus_space_read_region_4(sc->iot, sc->cfg_ioh, sc->cfgoff,
155 	    (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
156 
157 	if (sc->cfg.signature != CISS_SIGNATURE) {
158 		printf(": bad sign 0x%08x\n", sc->cfg.signature);
159 		return -1;
160 	}
161 
162 	if (!(sc->cfg.methods & CISS_METH_SIMPL)) {
163 		printf(": not simple 0x%08x\n", sc->cfg.methods);
164 		return -1;
165 	}
166 
167 	sc->cfg.rmethod = CISS_METH_SIMPL;
168 	sc->cfg.paddr_lim = 0;			/* 32bit addrs */
169 	sc->cfg.int_delay = 0;			/* disable coalescing */
170 	sc->cfg.int_count = 0;
171 	strlcpy(sc->cfg.hostname, "HUMPPA", sizeof(sc->cfg.hostname));
172 	sc->cfg.driverf |= CISS_DRV_PRF;	/* enable prefetch */
173 	if (!sc->cfg.maxsg)
174 		sc->cfg.maxsg = MAXPHYS / PAGE_SIZE;
175 
176 	bus_space_write_region_4(sc->iot, sc->cfg_ioh, sc->cfgoff,
177 	    (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
178 	bus_space_barrier(sc->iot, sc->cfg_ioh, sc->cfgoff, sizeof(sc->cfg),
179 	    BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
180 
181 	bus_space_write_4(sc->iot, sc->ioh, CISS_IDB, CISS_IDB_CFG);
182 	bus_space_barrier(sc->iot, sc->ioh, CISS_IDB, 4,
183 	    BUS_SPACE_BARRIER_WRITE);
184 	for (i = 1000; i--; DELAY(1000)) {
185 		/* XXX maybe IDB is really 64bit? - hp dl380 needs this */
186 		(void)bus_space_read_4(sc->iot, sc->ioh, CISS_IDB + 4);
187 		if (!(bus_space_read_4(sc->iot, sc->ioh, CISS_IDB) & CISS_IDB_CFG))
188 			break;
189 		bus_space_barrier(sc->iot, sc->ioh, CISS_IDB, 4,
190 		    BUS_SPACE_BARRIER_READ);
191 	}
192 
193 	if (bus_space_read_4(sc->iot, sc->ioh, CISS_IDB) & CISS_IDB_CFG) {
194 		printf(": cannot set config\n");
195 		return -1;
196 	}
197 
198 	bus_space_read_region_4(sc->iot, sc->cfg_ioh, sc->cfgoff,
199 	    (u_int32_t *)&sc->cfg, sizeof(sc->cfg) / 4);
200 
201 	if (!(sc->cfg.amethod & CISS_METH_SIMPL)) {
202 		printf(": cannot simplify 0x%08x\n", sc->cfg.amethod);
203 		return -1;
204 	}
205 
206 	/* i'm ready for you and i hope you're ready for me */
207 	for (i = 30000; i--; DELAY(1000)) {
208 		if (bus_space_read_4(sc->iot, sc->cfg_ioh, sc->cfgoff +
209 		    offsetof(struct ciss_config, amethod)) & CISS_METH_READY)
210 			break;
211 		bus_space_barrier(sc->iot, sc->cfg_ioh, sc->cfgoff +
212 		    offsetof(struct ciss_config, amethod), 4,
213 		    BUS_SPACE_BARRIER_READ);
214 	}
215 
216 	if (!(bus_space_read_4(sc->iot, sc->cfg_ioh, sc->cfgoff +
217 	    offsetof(struct ciss_config, amethod)) & CISS_METH_READY)) {
218 		printf(": she never came ready for me 0x%08x\n",
219 		    sc->cfg.amethod);
220 		return -1;
221 	}
222 
223 	sc->maxcmd = sc->cfg.maxcmd;
224 	sc->maxsg = sc->cfg.maxsg;
225 	if (sc->maxsg > MAXPHYS / PAGE_SIZE)
226 		sc->maxsg = MAXPHYS / PAGE_SIZE;
227 	i = sizeof(struct ciss_ccb) +
228 	    sizeof(ccb->ccb_cmd.sgl[0]) * (sc->maxsg - 1);
229 	for (sc->ccblen = 0x10; sc->ccblen < i; sc->ccblen <<= 1);
230 
231 	total = sc->ccblen * sc->maxcmd;
232 	if ((error = bus_dmamem_alloc(sc->dmat, total, PAGE_SIZE, 0,
233 	    sc->cmdseg, 1, &rseg, BUS_DMA_NOWAIT))) {
234 		printf(": cannot allocate CCBs (%d)\n", error);
235 		return -1;
236 	}
237 
238 	if ((error = bus_dmamem_map(sc->dmat, sc->cmdseg, rseg, total,
239 	    (caddr_t *)&sc->ccbs, BUS_DMA_NOWAIT))) {
240 		printf(": cannot map CCBs (%d)\n", error);
241 		return -1;
242 	}
243 	bzero(sc->ccbs, total);
244 
245 	if ((error = bus_dmamap_create(sc->dmat, total, 1,
246 	    total, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &sc->cmdmap))) {
247 		printf(": cannot create CCBs dmamap (%d)\n", error);
248 		bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
249 		return -1;
250 	}
251 
252 	if ((error = bus_dmamap_load(sc->dmat, sc->cmdmap, sc->ccbs, total,
253 	    NULL, BUS_DMA_NOWAIT))) {
254 		printf(": cannot load CCBs dmamap (%d)\n", error);
255 		bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
256 		bus_dmamap_destroy(sc->dmat, sc->cmdmap);
257 		return -1;
258 	}
259 
260 	TAILQ_INIT(&sc->sc_ccbq);
261 	TAILQ_INIT(&sc->sc_ccbdone);
262 	TAILQ_INIT(&sc->sc_free_ccb);
263 
264 	maxfer = sc->maxsg * PAGE_SIZE;
265 	for (i = 0; total; i++, total -= sc->ccblen) {
266 		ccb = sc->ccbs + i * sc->ccblen;
267 		cmd = &ccb->ccb_cmd;
268 		pa = sc->cmdseg[0].ds_addr + i * sc->ccblen;
269 
270 		ccb->ccb_sc = sc;
271 		ccb->ccb_cmdpa = pa + offsetof(struct ciss_ccb, ccb_cmd);
272 		ccb->ccb_state = CISS_CCB_FREE;
273 
274 		cmd->id = htole32(i << 2);
275 		cmd->id_hi = htole32(0);
276 		cmd->sgin = sc->maxsg;
277 		cmd->sglen = htole16((u_int16_t)cmd->sgin);
278 		cmd->err_len = htole32(sizeof(ccb->ccb_err));
279 		pa += offsetof(struct ciss_ccb, ccb_err);
280 		cmd->err_pa = htole64((u_int64_t)pa);
281 
282 		if ((error = bus_dmamap_create(sc->dmat, maxfer, sc->maxsg,
283 		    maxfer, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,
284 		    &ccb->ccb_dmamap)))
285 			break;
286 
287 		TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link);
288 	}
289 
290 	if (i < sc->maxcmd) {
291 		printf(": cannot create ccb#%d dmamap (%d)\n", i, error);
292 		if (i == 0) {
293 			/* TODO leaking cmd's dmamaps and shitz */
294 			bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
295 			bus_dmamap_destroy(sc->dmat, sc->cmdmap);
296 			return -1;
297 		}
298 	}
299 
300 	if ((error = bus_dmamem_alloc(sc->dmat, PAGE_SIZE, PAGE_SIZE, 0,
301 	    seg, 1, &rseg, BUS_DMA_NOWAIT))) {
302 		printf(": cannot allocate scratch buffer (%d)\n", error);
303 		return -1;
304 	}
305 
306 	if ((error = bus_dmamem_map(sc->dmat, seg, rseg, PAGE_SIZE,
307 	    (caddr_t *)&sc->scratch, BUS_DMA_NOWAIT))) {
308 		printf(": cannot map scratch buffer (%d)\n", error);
309 		return -1;
310 	}
311 	bzero(sc->scratch, PAGE_SIZE);
312 
313 	lock = CISS_LOCK_SCRATCH(sc);
314 	inq = sc->scratch;
315 	if (ciss_inq(sc, inq)) {
316 		printf(": adapter inquiry failed\n");
317 		CISS_UNLOCK_SCRATCH(sc, lock);
318 		bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
319 		bus_dmamap_destroy(sc->dmat, sc->cmdmap);
320 		return -1;
321 	}
322 
323 	if (!(inq->flags & CISS_INQ_BIGMAP)) {
324 		printf(": big map is not supported, flags=%b\n",
325 		    inq->flags, CISS_INQ_BITS);
326 		CISS_UNLOCK_SCRATCH(sc, lock);
327 		bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
328 		bus_dmamap_destroy(sc->dmat, sc->cmdmap);
329 		return -1;
330 	}
331 
332 	sc->maxunits = inq->numld;
333 	sc->nbus = inq->nscsi_bus;
334 	sc->ndrives = inq->buswidth? inq->buswidth : 256;
335 	printf(": %d LD%s, HW rev %d, FW %4.4s/%4.4s\n",
336 	    inq->numld, inq->numld == 1? "" : "s",
337 	    inq->hw_rev, inq->fw_running, inq->fw_stored);
338 
339 	CISS_UNLOCK_SCRATCH(sc, lock);
340 
341 	timeout_set(&sc->sc_hb, ciss_heartbeat, sc);
342 	timeout_add_sec(&sc->sc_hb, 3);
343 
344 	/* map LDs */
345 	if (ciss_ldmap(sc)) {
346 		printf("%s: adapter LD map failed\n", sc->sc_dev.dv_xname);
347 		bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
348 		bus_dmamap_destroy(sc->dmat, sc->cmdmap);
349 		return -1;
350 	}
351 
352 	if (!(sc->sc_lds = malloc(sc->maxunits * sizeof(*sc->sc_lds),
353 	    M_DEVBUF, M_NOWAIT | M_ZERO))) {
354 		bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
355 		bus_dmamap_destroy(sc->dmat, sc->cmdmap);
356 		return -1;
357 	}
358 
359 	sc->sc_flush = CISS_FLUSH_ENABLE;
360 	if (!(sc->sc_sh = shutdownhook_establish(ciss_shutdown, sc))) {
361 		printf(": unable to establish shutdown hook\n");
362 		bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
363 		bus_dmamap_destroy(sc->dmat, sc->cmdmap);
364 		return -1;
365 	}
366 
367 #if 0
368 	if (kthread_create(ciss_kthread, sc, NULL, "%s", sc->sc_dev.dv_xname)) {
369 		printf(": unable to create kernel thread\n");
370 		shutdownhook_disestablish(sc->sc_sh);
371 		bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
372 		bus_dmamap_destroy(sc->dmat, sc->cmdmap);
373 		return -1;
374 	}
375 #endif
376 
377 	sc->sc_link.device = &ciss_dev;
378 	sc->sc_link.adapter_softc = sc;
379 	sc->sc_link.openings = sc->maxcmd / (sc->maxunits? sc->maxunits : 1);
380 #if NBIO > 0
381 	/* XXX Reserve some ccb's for sensor and bioctl. */
382 	if (sc->maxunits < 2 && sc->sc_link.openings > 2)
383 		sc->sc_link.openings -= 2;
384 #endif
385 	sc->sc_link.adapter = &ciss_switch;
386 	sc->sc_link.adapter_target = sc->maxunits;
387 	sc->sc_link.adapter_buswidth = sc->maxunits;
388 	bzero(&saa, sizeof(saa));
389 	saa.saa_sc_link = &sc->sc_link;
390 	scsibus = (struct scsibus_softc *)config_found_sm(&sc->sc_dev,
391 	    &saa, scsiprint, NULL);
392 
393 #if 0
394 	sc->sc_link_raw.device = &ciss_raw_dev;
395 	sc->sc_link_raw.adapter_softc = sc;
396 	sc->sc_link.openings = sc->maxcmd / (sc->maxunits? sc->maxunits : 1);
397 	sc->sc_link_raw.adapter = &ciss_raw_switch;
398 	sc->sc_link_raw.adapter_target = sc->ndrives;
399 	sc->sc_link_raw.adapter_buswidth = sc->ndrives;
400 	bzero(&saa, sizeof(saa));
401 	saa.saa_sc_link = &sc->sc_link_raw;
402 	rawbus = (struct scsibus_softc *)config_found_sm(&sc->sc_dev,
403 	    &saa, scsiprint, NULL);
404 #endif
405 
406 #if NBIO > 0
407 	/* XXX for now we can only deal w/ one volume and need reserved ccbs. */
408 	if (!scsibus || sc->maxunits > 1 || sc->sc_link.openings == sc->maxcmd)
409 		return 0;
410 
411 	/* now map all the physdevs into their lds */
412 	/* XXX currently we assign all pf 'em into ld#0 */
413 	for (i = 0; i < sc->maxunits; i++)
414 		if (!(sc->sc_lds[i] = ciss_pdscan(sc, i)))
415 			return 0;
416 
417 	if (bio_register(&sc->sc_dev, ciss_ioctl) != 0)
418 		printf("%s: controller registration failed",
419 		    sc->sc_dev.dv_xname);
420 
421 	sc->sc_flags |= CISS_BIO;
422 #ifndef SMALL_KERNEL
423 	sc->sensors = malloc(sizeof(struct ksensor) * sc->maxunits,
424 	    M_DEVBUF, M_NOWAIT | M_ZERO);
425 	if (sc->sensors) {
426 		strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
427 		    sizeof(sc->sensordev.xname));
428 		for (i = 0; i < sc->maxunits;
429 		    sensor_attach(&sc->sensordev, &sc->sensors[i++])) {
430 			sc->sensors[i].type = SENSOR_DRIVE;
431 			sc->sensors[i].status = SENSOR_S_UNKNOWN;
432 			strlcpy(sc->sensors[i].desc, ((struct device *)
433 			    scsibus->sc_link[i][0]->device_softc)->dv_xname,
434 			    sizeof(sc->sensors[i].desc));
435 			strlcpy(sc->sc_lds[i]->xname, ((struct device *)
436 			    scsibus->sc_link[i][0]->device_softc)->dv_xname,
437 			    sizeof(sc->sc_lds[i]->xname));
438 		}
439 		if (sensor_task_register(sc, ciss_sensors, 10) == NULL)
440 			free(sc->sensors, M_DEVBUF);
441 		else
442 			sensordev_install(&sc->sensordev);
443 	}
444 #endif /* SMALL_KERNEL */
445 #endif /* BIO > 0 */
446 
447 	return 0;
448 }
449 
450 void
451 ciss_shutdown(void *v)
452 {
453 	struct ciss_softc *sc = v;
454 
455 	sc->sc_flush = CISS_FLUSH_DISABLE;
456 	timeout_del(&sc->sc_hb);
457 	ciss_sync(sc);
458 }
459 
460 void
461 cissminphys(struct buf *bp, struct scsi_link *sl)
462 {
463 #if 0	/* TODO */
464 #define	CISS_MAXFER	(PAGE_SIZE * (sc->maxsg + 1))
465 	if (bp->b_bcount > CISS_MAXFER)
466 		bp->b_bcount = CISS_MAXFER;
467 #endif
468 	minphys(bp);
469 }
470 
471 /*
472  * submit a command and optionally wait for completition.
473  * wait arg abuses SCSI_POLL|SCSI_NOSLEEP flags to request
474  * to wait (SCSI_POLL) and to allow tsleep() (!SCSI_NOSLEEP)
475  * instead of busy loop waiting
476  */
477 int
478 ciss_cmd(struct ciss_ccb *ccb, int flags, int wait)
479 {
480 	struct ciss_softc *sc = ccb->ccb_sc;
481 	struct ciss_cmd *cmd = &ccb->ccb_cmd;
482 	struct ciss_ccb *ccb1;
483 	bus_dmamap_t dmap = ccb->ccb_dmamap;
484 	u_int32_t id;
485 	int i, tohz, error = 0;
486 
487 	if (ccb->ccb_state != CISS_CCB_READY) {
488 		printf("%s: ccb %d not ready state=%b\n", sc->sc_dev.dv_xname,
489 		    cmd->id, ccb->ccb_state, CISS_CCB_BITS);
490 		return (EINVAL);
491 	}
492 
493 	if (ccb->ccb_data) {
494 		bus_dma_segment_t *sgd;
495 
496 		if ((error = bus_dmamap_load(sc->dmat, dmap, ccb->ccb_data,
497 		    ccb->ccb_len, NULL, flags))) {
498 			if (error == EFBIG)
499 				printf("more than %d dma segs\n", sc->maxsg);
500 			else
501 				printf("error %d loading dma map\n", error);
502 			ciss_put_ccb(ccb);
503 			return (error);
504 		}
505 		cmd->sgin = dmap->dm_nsegs;
506 
507 		sgd = dmap->dm_segs;
508 		CISS_DPRINTF(CISS_D_DMA, ("data=%p/%u<0x%lx/%u",
509 		    ccb->ccb_data, ccb->ccb_len, sgd->ds_addr, sgd->ds_len));
510 
511 		for (i = 0; i < dmap->dm_nsegs; sgd++, i++) {
512 			cmd->sgl[i].addr_lo = htole32(sgd->ds_addr);
513 			cmd->sgl[i].addr_hi =
514 			    htole32((u_int64_t)sgd->ds_addr >> 32);
515 			cmd->sgl[i].len = htole32(sgd->ds_len);
516 			cmd->sgl[i].flags = htole32(0);
517 			if (i)
518 				CISS_DPRINTF(CISS_D_DMA,
519 				    (",0x%lx/%u", sgd->ds_addr, sgd->ds_len));
520 		}
521 
522 		CISS_DPRINTF(CISS_D_DMA, ("> "));
523 
524 		bus_dmamap_sync(sc->dmat, dmap, 0, dmap->dm_mapsize,
525 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
526 	} else
527 		cmd->sgin = 0;
528 	cmd->sglen = htole16((u_int16_t)cmd->sgin);
529 	bzero(&ccb->ccb_err, sizeof(ccb->ccb_err));
530 
531 	bus_dmamap_sync(sc->dmat, sc->cmdmap, 0, sc->cmdmap->dm_mapsize,
532 	    BUS_DMASYNC_PREWRITE);
533 
534 	if ((wait & (SCSI_POLL|SCSI_NOSLEEP)) == (SCSI_POLL|SCSI_NOSLEEP))
535 		bus_space_write_4(sc->iot, sc->ioh, CISS_IMR,
536 		    bus_space_read_4(sc->iot, sc->ioh, CISS_IMR) | sc->iem);
537 
538 	TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ccb_link);
539 	ccb->ccb_state = CISS_CCB_ONQ;
540 	CISS_DPRINTF(CISS_D_CMD, ("submit=0x%x ", cmd->id));
541 	bus_space_write_4(sc->iot, sc->ioh, CISS_INQ, ccb->ccb_cmdpa);
542 
543 	if (wait & SCSI_POLL) {
544 		struct timeval tv;
545 		int etick;
546 		CISS_DPRINTF(CISS_D_CMD, ("waiting "));
547 
548 		i = ccb->ccb_xs? ccb->ccb_xs->timeout : 60000;
549 		tv.tv_sec = i / 1000;
550 		tv.tv_usec = (i % 1000) * 1000;
551 		tohz = tvtohz(&tv);
552 		if (tohz == 0)
553 			tohz = 1;
554 		for (i *= 100, etick = tick + tohz; i--; ) {
555 			if (!(wait & SCSI_NOSLEEP)) {
556 				ccb->ccb_state = CISS_CCB_POLL;
557 				CISS_DPRINTF(CISS_D_CMD, ("tsleep(%d) ", tohz));
558 				if (tsleep(ccb, PRIBIO + 1, "ciss_cmd",
559 				    tohz) == EWOULDBLOCK) {
560 					break;
561 				}
562 				if (ccb->ccb_state != CISS_CCB_ONQ) {
563 					tohz = etick - tick;
564 					if (tohz <= 0)
565 						break;
566 					CISS_DPRINTF(CISS_D_CMD, ("T"));
567 					continue;
568 				}
569 				ccb1 = ccb;
570 			} else {
571 				DELAY(10);
572 
573 				if (!(bus_space_read_4(sc->iot, sc->ioh,
574 				    CISS_ISR) & sc->iem)) {
575 					CISS_DPRINTF(CISS_D_CMD, ("N"));
576 					continue;
577 				}
578 
579 				if ((id = bus_space_read_4(sc->iot, sc->ioh,
580 				    CISS_OUTQ)) == 0xffffffff) {
581 					CISS_DPRINTF(CISS_D_CMD, ("Q"));
582 					continue;
583 				}
584 
585 				CISS_DPRINTF(CISS_D_CMD, ("got=0x%x ", id));
586 				ccb1 = sc->ccbs + (id >> 2) * sc->ccblen;
587 				ccb1->ccb_cmd.id = htole32(id);
588 			}
589 
590 			error = ciss_done(ccb1);
591 			if (ccb1 == ccb)
592 				break;
593 		}
594 
595 		/* if never got a chance to be done above... */
596 		if (ccb->ccb_state != CISS_CCB_FREE) {
597 			ccb->ccb_err.cmd_stat = CISS_ERR_TMO;
598 			error = ciss_done(ccb);
599 		}
600 
601 		CISS_DPRINTF(CISS_D_CMD, ("done %d:%d",
602 		    ccb->ccb_err.cmd_stat, ccb->ccb_err.scsi_stat));
603 	}
604 
605 	if ((wait & (SCSI_POLL|SCSI_NOSLEEP)) == (SCSI_POLL|SCSI_NOSLEEP))
606 		bus_space_write_4(sc->iot, sc->ioh, CISS_IMR,
607 		    bus_space_read_4(sc->iot, sc->ioh, CISS_IMR) & ~sc->iem);
608 
609 	return (error);
610 }
611 
612 int
613 ciss_done(struct ciss_ccb *ccb)
614 {
615 	struct ciss_softc *sc = ccb->ccb_sc;
616 	struct scsi_xfer *xs = ccb->ccb_xs;
617 	ciss_lock_t lock;
618 	int error = 0;
619 
620 	CISS_DPRINTF(CISS_D_CMD, ("ciss_done(%p) ", ccb));
621 
622 	if (ccb->ccb_state != CISS_CCB_ONQ) {
623 		printf("%s: unqueued ccb %p ready, state=%b\n",
624 		    sc->sc_dev.dv_xname, ccb, ccb->ccb_state, CISS_CCB_BITS);
625 		return 1;
626 	}
627 
628 	lock = CISS_LOCK(sc);
629 	ccb->ccb_state = CISS_CCB_READY;
630 	TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link);
631 
632 	if (ccb->ccb_cmd.id & CISS_CMD_ERR)
633 		error = ciss_error(ccb);
634 
635 	if (ccb->ccb_data) {
636 		bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap, 0,
637 		    ccb->ccb_dmamap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ?
638 		    BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
639 		bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);
640 		ccb->ccb_xs = NULL;
641 		ccb->ccb_data = NULL;
642 	}
643 
644 	ciss_put_ccb(ccb);
645 
646 	if (xs) {
647 		xs->resid = 0;
648 		xs->flags |= ITSDONE;
649 		CISS_DPRINTF(CISS_D_CMD, ("scsi_done(%p) ", xs));
650 		scsi_done(xs);
651 	}
652 	CISS_UNLOCK(sc, lock);
653 
654 	return error;
655 }
656 
657 int
658 ciss_error(struct ciss_ccb *ccb)
659 {
660 	struct ciss_softc *sc = ccb->ccb_sc;
661 	struct ciss_error *err = &ccb->ccb_err;
662 	struct scsi_xfer *xs = ccb->ccb_xs;
663 	int rv;
664 
665 	switch ((rv = letoh16(err->cmd_stat))) {
666 	case CISS_ERR_OK:
667 		rv = 0;
668 		break;
669 
670 	case CISS_ERR_INVCMD:
671 		printf("%s: invalid cmd 0x%x: 0x%x is not valid @ 0x%x[%d]\n",
672 		    sc->sc_dev.dv_xname, ccb->ccb_cmd.id,
673 		    err->err_info, err->err_type[3], err->err_type[2]);
674 		if (xs) {
675 			bzero(&xs->sense, sizeof(xs->sense));
676 			xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
677 			xs->sense.flags = SKEY_ILLEGAL_REQUEST;
678 			xs->sense.add_sense_code = 0x24; /* ill field */
679 			xs->error = XS_SENSE;
680 		}
681 		rv = EIO;
682 		break;
683 
684 	case CISS_ERR_TMO:
685 		xs->error = XS_TIMEOUT;
686 		rv = ETIMEDOUT;
687 		break;
688 
689 	default:
690 		if (xs) {
691 			switch (err->scsi_stat) {
692 			case SCSI_CHECK:
693 				xs->error = XS_SENSE;
694 				bcopy(&err->sense[0], &xs->sense,
695 				    sizeof(xs->sense));
696 				rv = EIO;
697 				break;
698 
699 			case SCSI_BUSY:
700 				xs->error = XS_BUSY;
701 				rv = EBUSY;
702 				break;
703 
704 			default:
705 				CISS_DPRINTF(CISS_D_ERR, ("%s: "
706 				    "cmd_stat %x scsi_stat 0x%x\n",
707 				    sc->sc_dev.dv_xname, rv, err->scsi_stat));
708 				xs->error = XS_DRIVER_STUFFUP;
709 				rv = EIO;
710 				break;
711 			}
712 			xs->resid = letoh32(err->resid);
713 		} else
714 			rv = EIO;
715 	}
716 	ccb->ccb_cmd.id &= htole32(~3);
717 
718 	return rv;
719 }
720 
721 int
722 ciss_inq(struct ciss_softc *sc, struct ciss_inquiry *inq)
723 {
724 	struct ciss_ccb *ccb;
725 	struct ciss_cmd *cmd;
726 
727 	ccb = ciss_get_ccb(sc);
728 	ccb->ccb_len = sizeof(*inq);
729 	ccb->ccb_data = inq;
730 	cmd = &ccb->ccb_cmd;
731 	cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
732 	cmd->tgt2 = 0;
733 	cmd->cdblen = 10;
734 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
735 	cmd->tmo = htole16(0);
736 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
737 	cmd->cdb[0] = CISS_CMD_CTRL_GET;
738 	cmd->cdb[6] = CISS_CMS_CTRL_CTRL;
739 	cmd->cdb[7] = sizeof(*inq) >> 8;	/* biiiig endian */
740 	cmd->cdb[8] = sizeof(*inq) & 0xff;
741 
742 	return ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
743 }
744 
745 int
746 ciss_ldmap(struct ciss_softc *sc)
747 {
748 	struct ciss_ccb *ccb;
749 	struct ciss_cmd *cmd;
750 	struct ciss_ldmap *lmap;
751 	ciss_lock_t lock;
752 	int total, rv;
753 
754 	lock = CISS_LOCK_SCRATCH(sc);
755 	lmap = sc->scratch;
756 	lmap->size = htobe32(sc->maxunits * sizeof(lmap->map));
757 	total = sizeof(*lmap) + (sc->maxunits - 1) * sizeof(lmap->map);
758 
759 	ccb = ciss_get_ccb(sc);
760 	ccb->ccb_len = total;
761 	ccb->ccb_data = lmap;
762 	cmd = &ccb->ccb_cmd;
763 	cmd->tgt = CISS_CMD_MODE_PERIPH;
764 	cmd->tgt2 = 0;
765 	cmd->cdblen = 12;
766 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
767 	cmd->tmo = htole16(30);
768 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
769 	cmd->cdb[0] = CISS_CMD_LDMAP;
770 	cmd->cdb[8] = total >> 8;	/* biiiig endian */
771 	cmd->cdb[9] = total & 0xff;
772 
773 	rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
774 	CISS_UNLOCK_SCRATCH(sc, lock);
775 
776 	if (rv)
777 		return rv;
778 
779 	CISS_DPRINTF(CISS_D_MISC, ("lmap %x:%x\n",
780 	    lmap->map[0].tgt, lmap->map[0].tgt2));
781 
782 	return 0;
783 }
784 
785 int
786 ciss_sync(struct ciss_softc *sc)
787 {
788 	struct ciss_ccb *ccb;
789 	struct ciss_cmd *cmd;
790 	struct ciss_flush *flush;
791 	ciss_lock_t lock;
792 	int rv;
793 
794 	lock = CISS_LOCK_SCRATCH(sc);
795 	flush = sc->scratch;
796 	bzero(flush, sizeof(*flush));
797 	flush->flush = sc->sc_flush;
798 
799 	ccb = ciss_get_ccb(sc);
800 	ccb->ccb_len = sizeof(*flush);
801 	ccb->ccb_data = flush;
802 	cmd = &ccb->ccb_cmd;
803 	cmd->tgt = CISS_CMD_MODE_PERIPH;
804 	cmd->tgt2 = 0;
805 	cmd->cdblen = 10;
806 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_OUT;
807 	cmd->tmo = htole16(0);
808 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
809 	cmd->cdb[0] = CISS_CMD_CTRL_SET;
810 	cmd->cdb[6] = CISS_CMS_CTRL_FLUSH;
811 	cmd->cdb[7] = sizeof(*flush) >> 8;	/* biiiig endian */
812 	cmd->cdb[8] = sizeof(*flush) & 0xff;
813 
814 	rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
815 	CISS_UNLOCK_SCRATCH(sc, lock);
816 
817 	return rv;
818 }
819 
820 int
821 ciss_scsi_raw_cmd(struct scsi_xfer *xs)	/* TODO */
822 {
823 	struct scsi_link *link = xs->sc_link;
824 	struct ciss_rawsoftc *rsc = link->adapter_softc;
825 	struct ciss_softc *sc = rsc->sc_softc;
826 	struct ciss_ccb *ccb;
827 	struct ciss_cmd *cmd;
828 	ciss_lock_t lock;
829 
830 	CISS_DPRINTF(CISS_D_CMD, ("ciss_scsi_raw_cmd "));
831 
832 	lock = CISS_LOCK(sc);
833 	if (xs->cmdlen > CISS_MAX_CDB) {
834 		CISS_DPRINTF(CISS_D_CMD, ("CDB too big %p ", xs));
835 		bzero(&xs->sense, sizeof(xs->sense));
836 		xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
837 		xs->sense.flags = SKEY_ILLEGAL_REQUEST;
838 		xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
839 		xs->error = XS_SENSE;
840 		scsi_done(xs);
841 		CISS_UNLOCK(sc, lock);
842 		return (COMPLETE);
843 	}
844 
845 	xs->error = XS_NOERROR;
846 
847 	/* TODO check this target has not yet employed w/ any volume */
848 
849 	ccb = ciss_get_ccb(sc);
850 	cmd = &ccb->ccb_cmd;
851 	ccb->ccb_len = xs->datalen;
852 	ccb->ccb_data = xs->data;
853 	ccb->ccb_xs = xs;
854 
855 
856 
857 	cmd->cdblen = xs->cmdlen;
858 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL;
859 	if (xs->flags & SCSI_DATA_IN)
860 		cmd->flags |= CISS_CDB_IN;
861 	else if (xs->flags & SCSI_DATA_OUT)
862 		cmd->flags |= CISS_CDB_OUT;
863 	cmd->tmo = htole16(xs->timeout < 1000? 1 : xs->timeout / 1000);
864 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
865 	bcopy(xs->cmd, &cmd->cdb[0], CISS_MAX_CDB);
866 
867 	if (ciss_cmd(ccb, BUS_DMA_WAITOK,
868 	    xs->flags & (SCSI_POLL|SCSI_NOSLEEP))) {
869 		xs->error = XS_DRIVER_STUFFUP;
870 		scsi_done(xs);
871 		CISS_UNLOCK(sc, lock);
872 		return (COMPLETE);
873 	}
874 
875 	CISS_UNLOCK(sc, lock);
876 	return xs->flags & SCSI_POLL? COMPLETE : SUCCESSFULLY_QUEUED;
877 }
878 
879 int
880 ciss_scsi_cmd(struct scsi_xfer *xs)
881 {
882 	struct scsi_link *link = xs->sc_link;
883 	struct ciss_softc *sc = link->adapter_softc;
884 	u_int8_t target = link->target;
885 	struct ciss_ccb *ccb;
886 	struct ciss_cmd *cmd;
887 	ciss_lock_t lock;
888 
889 	CISS_DPRINTF(CISS_D_CMD, ("ciss_scsi_cmd "));
890 
891 	lock = CISS_LOCK(sc);
892 	if (xs->cmdlen > CISS_MAX_CDB) {
893 		CISS_DPRINTF(CISS_D_CMD, ("CDB too big %p ", xs));
894 		bzero(&xs->sense, sizeof(xs->sense));
895 		xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
896 		xs->sense.flags = SKEY_ILLEGAL_REQUEST;
897 		xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
898 		xs->error = XS_SENSE;
899 		scsi_done(xs);
900 		CISS_UNLOCK(sc, lock);
901 		return (COMPLETE);
902 	}
903 
904 	xs->error = XS_NOERROR;
905 
906 	/* XXX emulate SYNCHRONIZE_CACHE ??? */
907 
908 	ccb = ciss_get_ccb(sc);
909 	cmd = &ccb->ccb_cmd;
910 	ccb->ccb_len = xs->datalen;
911 	ccb->ccb_data = xs->data;
912 	ccb->ccb_xs = xs;
913 	cmd->tgt = CISS_CMD_MODE_LD | target;
914 	cmd->tgt2 = 0;
915 	cmd->cdblen = xs->cmdlen;
916 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL;
917 	if (xs->flags & SCSI_DATA_IN)
918 		cmd->flags |= CISS_CDB_IN;
919 	else if (xs->flags & SCSI_DATA_OUT)
920 		cmd->flags |= CISS_CDB_OUT;
921 	cmd->tmo = htole16(xs->timeout < 1000? 1 : xs->timeout / 1000);
922 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
923 	bcopy(xs->cmd, &cmd->cdb[0], CISS_MAX_CDB);
924 
925 	if (ciss_cmd(ccb, BUS_DMA_WAITOK,
926 	    xs->flags & (SCSI_POLL|SCSI_NOSLEEP))) {
927 		xs->error = XS_DRIVER_STUFFUP;
928 		scsi_done(xs);
929 		CISS_UNLOCK(sc, lock);
930 		return (COMPLETE);
931 	}
932 
933 	CISS_UNLOCK(sc, lock);
934 	return xs->flags & SCSI_POLL? COMPLETE : SUCCESSFULLY_QUEUED;
935 }
936 
937 int
938 ciss_intr(void *v)
939 {
940 	struct ciss_softc *sc = v;
941 	struct ciss_ccb *ccb;
942 	ciss_lock_t lock;
943 	u_int32_t id;
944 	int hit = 0;
945 
946 	CISS_DPRINTF(CISS_D_INTR, ("intr "));
947 
948 	if (!(bus_space_read_4(sc->iot, sc->ioh, CISS_ISR) & sc->iem))
949 		return 0;
950 
951 	lock = CISS_LOCK(sc);
952 	while ((id = bus_space_read_4(sc->iot, sc->ioh, CISS_OUTQ)) !=
953 	    0xffffffff) {
954 
955 		ccb = sc->ccbs + (id >> 2) * sc->ccblen;
956 		ccb->ccb_cmd.id = htole32(id);
957 		if (ccb->ccb_state == CISS_CCB_POLL) {
958 			ccb->ccb_state = CISS_CCB_ONQ;
959 			wakeup(ccb);
960 		} else
961 			ciss_done(ccb);
962 
963 		hit = 1;
964 	}
965 	CISS_UNLOCK(sc, lock);
966 
967 	CISS_DPRINTF(CISS_D_INTR, ("exit "));
968 	return hit;
969 }
970 
971 void
972 ciss_heartbeat(void *v)
973 {
974 	struct ciss_softc *sc = v;
975 	u_int32_t hb;
976 
977 	hb = bus_space_read_4(sc->iot, sc->cfg_ioh,
978 	    sc->cfgoff + offsetof(struct ciss_config, heartbeat));
979 	if (hb == sc->heartbeat)
980 		panic("%s: dead", sc->sc_dev.dv_xname);	/* XXX reset! */
981 	else
982 		sc->heartbeat = hb;
983 
984 	timeout_add_sec(&sc->sc_hb, 3);
985 }
986 
987 void
988 ciss_kthread(void *v)
989 {
990 	struct ciss_softc *sc = v;
991 	ciss_lock_t lock;
992 
993 	for (;;) {
994 		tsleep(sc, PRIBIO, sc->sc_dev.dv_xname, 0);
995 
996 		lock = CISS_LOCK(sc);
997 
998 
999 
1000 		CISS_UNLOCK(sc, lock);
1001 	}
1002 }
1003 
1004 int
1005 ciss_scsi_ioctl(struct scsi_link *link, u_long cmd,
1006     caddr_t addr, int flag, struct proc *p)
1007 {
1008 #if NBIO > 0
1009 	return ciss_ioctl(link->adapter_softc, cmd, addr);
1010 #else
1011 	return ENOTTY;
1012 #endif
1013 }
1014 
1015 #if NBIO > 0
1016 const int ciss_level[] = { 0, 4, 1, 5, 51, 7 };
1017 const int ciss_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
1018     BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
1019     BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
1020     BIOC_SVOFFLINE, BIOC_SVBUILDING };
1021 
1022 int
1023 ciss_ioctl(struct device *dev, u_long cmd, caddr_t addr)
1024 {
1025 	struct ciss_softc *sc = (struct ciss_softc *)dev;
1026 	struct bioc_inq *bi;
1027 	struct bioc_vol *bv;
1028 	struct bioc_disk *bd;
1029 	struct bioc_blink *bb;
1030 	/* struct bioc_alarm *ba; */
1031 	/* struct bioc_setstate *bss; */
1032 	struct ciss_ldid *ldid;
1033 	struct ciss_ldstat *ldstat;
1034 	struct ciss_pdid *pdid;
1035 	struct ciss_blink *blink;
1036 	struct ciss_ld *ldp;
1037 	ciss_lock_t lock;
1038 	u_int8_t drv;
1039 	int ld, pd, error = 0;
1040 	u_int blks;
1041 
1042 	if (!(sc->sc_flags & CISS_BIO))
1043 		return ENOTTY;
1044 
1045 	lock = CISS_LOCK(sc);
1046 	switch (cmd) {
1047 	case BIOCINQ:
1048 		bi = (struct bioc_inq *)addr;
1049 		strlcpy(bi->bi_dev, sc->sc_dev.dv_xname, sizeof(bi->bi_dev));
1050 		bi->bi_novol = sc->maxunits;
1051 		bi->bi_nodisk = sc->ndrives;
1052 		break;
1053 
1054 	case BIOCVOL:
1055 		bv = (struct bioc_vol *)addr;
1056 		if (bv->bv_volid > sc->maxunits) {
1057 			error = EINVAL;
1058 			break;
1059 		}
1060 		ldp = sc->sc_lds[bv->bv_volid];
1061 		if (!ldp)
1062 			return EINVAL;
1063 		ldid = sc->scratch;
1064 		if ((error = ciss_ldid(sc, bv->bv_volid, ldid)))
1065 			break;
1066 		/* params 30:88:ff:00:00:00:00:00:00:00:00:00:00:00:20:00 */
1067 		bv->bv_status = BIOC_SVINVALID;
1068 		blks = (u_int)letoh16(ldid->nblocks[1]) << 16 |
1069 		    letoh16(ldid->nblocks[0]);
1070 		bv->bv_size = blks * (u_quad_t)letoh16(ldid->blksize);
1071 		bv->bv_level = ciss_level[ldid->type];
1072 		bv->bv_nodisk = ldp->ndrives;
1073 		strlcpy(bv->bv_dev, ldp->xname, sizeof(bv->bv_dev));
1074 		strlcpy(bv->bv_vendor, "CISS", sizeof(bv->bv_vendor));
1075 		ldstat = sc->scratch;
1076 		bzero(ldstat, sizeof(*ldstat));
1077 		if ((error = ciss_ldstat(sc, bv->bv_volid, ldstat)))
1078 			break;
1079 		bv->bv_percent = -1;
1080 		bv->bv_seconds = 0;
1081 		if (ldstat->stat < sizeof(ciss_stat)/sizeof(ciss_stat[0]))
1082 			bv->bv_status = ciss_stat[ldstat->stat];
1083 		if (bv->bv_status == BIOC_SVREBUILD ||
1084 		    bv->bv_status == BIOC_SVBUILDING)
1085 			bv->bv_percent = (blks -
1086 			    (((u_int)ldstat->prog[3] << 24) |
1087 			    ((u_int)ldstat->prog[2] << 16) |
1088 			    ((u_int)ldstat->prog[1] << 8) |
1089 			    (u_int)ldstat->prog[0])) * 100ULL / blks;
1090 		break;
1091 
1092 	case BIOCDISK:
1093 		bd = (struct bioc_disk *)addr;
1094 		if (bd->bd_volid > sc->maxunits) {
1095 			error = EINVAL;
1096 			break;
1097 		}
1098 		ldp = sc->sc_lds[bd->bd_volid];
1099 		if (!ldp || (pd = bd->bd_diskid) > ldp->ndrives) {
1100 			error = EINVAL;
1101 			break;
1102 		}
1103 		ldstat = sc->scratch;
1104 		if ((error = ciss_ldstat(sc, bd->bd_volid, ldstat)))
1105 			break;
1106 		bd->bd_status = -1;
1107 		if (ldstat->stat == CISS_LD_REBLD &&
1108 		    ldstat->bigrebuild == ldp->tgts[pd])
1109 			bd->bd_status = BIOC_SDREBUILD;
1110 		if (ciss_bitset(ldp->tgts[pd] & (~CISS_BIGBIT),
1111 		    ldstat->bigfailed)) {
1112 			bd->bd_status = BIOC_SDFAILED;
1113 			bd->bd_size = 0;
1114 			bd->bd_channel = (ldp->tgts[pd] & (~CISS_BIGBIT)) /
1115 			    sc->ndrives;
1116 			bd->bd_target = ldp->tgts[pd] % sc->ndrives;
1117 			bd->bd_lun = 0;
1118 			bd->bd_vendor[0] = '\0';
1119 			bd->bd_serial[0] = '\0';
1120 			bd->bd_procdev[0] = '\0';
1121 		} else {
1122 			pdid = sc->scratch;
1123 			if ((error = ciss_pdid(sc, ldp->tgts[pd], pdid,
1124 			    SCSI_POLL)))
1125 				break;
1126 			if (bd->bd_status < 0) {
1127 				if (pdid->config & CISS_PD_SPARE)
1128 					bd->bd_status = BIOC_SDHOTSPARE;
1129 				else if (pdid->present & CISS_PD_PRESENT)
1130 					bd->bd_status = BIOC_SDONLINE;
1131 				else
1132 					bd->bd_status = BIOC_SDINVALID;
1133 			}
1134 			bd->bd_size = (u_int64_t)letoh32(pdid->nblocks) *
1135 			    letoh16(pdid->blksz);
1136 			bd->bd_channel = pdid->bus;
1137 			bd->bd_target = pdid->target;
1138 			bd->bd_lun = 0;
1139 			strlcpy(bd->bd_vendor, pdid->model,
1140 			    sizeof(bd->bd_vendor));
1141 			strlcpy(bd->bd_serial, pdid->serial,
1142 			    sizeof(bd->bd_serial));
1143 			bd->bd_procdev[0] = '\0';
1144 		}
1145 		break;
1146 
1147 	case BIOCBLINK:
1148 		bb = (struct bioc_blink *)addr;
1149 		blink = sc->scratch;
1150 		error = EINVAL;
1151 		/* XXX workaround completely dumb scsi addressing */
1152 		for (ld = 0; ld < sc->maxunits; ld++) {
1153 			ldp = sc->sc_lds[ld];
1154 			if (!ldp)
1155 				continue;
1156 			if (sc->ndrives == 256)
1157 				drv = bb->bb_target;
1158 			else
1159 				drv = CISS_BIGBIT +
1160 				    bb->bb_channel * sc->ndrives +
1161 				    bb->bb_target;
1162 			for (pd = 0; pd < ldp->ndrives; pd++)
1163 				if (ldp->tgts[pd] == drv)
1164 					error = ciss_blink(sc, ld, pd,
1165 					    bb->bb_status, blink);
1166 		}
1167 		break;
1168 
1169 	case BIOCALARM:
1170 	case BIOCSETSTATE:
1171 	default:
1172 		CISS_DPRINTF(CISS_D_IOCTL, ("%s: invalid ioctl\n",
1173 		    sc->sc_dev.dv_xname));
1174 		error = ENOTTY;
1175 	}
1176 	CISS_UNLOCK(sc, lock);
1177 
1178 	return error;
1179 }
1180 
1181 #ifndef SMALL_KERNEL
1182 void
1183 ciss_sensors(void *v)
1184 {
1185 	struct ciss_softc *sc = v;
1186 	struct ciss_ldstat *ldstat;
1187 	int i, error;
1188 
1189 	for (i = 0; i < sc->maxunits; i++) {
1190 		ldstat = sc->scratch;
1191 		if ((error = ciss_ldstat(sc, i, ldstat))) {
1192 			sc->sensors[i].value = 0;
1193 			sc->sensors[i].status = SENSOR_S_UNKNOWN;
1194 			continue;
1195 		}
1196 
1197 		switch (ldstat->stat) {
1198 		case CISS_LD_OK:
1199 			sc->sensors[i].value = SENSOR_DRIVE_ONLINE;
1200 			sc->sensors[i].status = SENSOR_S_OK;
1201 			break;
1202 
1203 		case CISS_LD_DEGRAD:
1204 			sc->sensors[i].value = SENSOR_DRIVE_PFAIL;
1205 			sc->sensors[i].status = SENSOR_S_WARN;
1206 			break;
1207 
1208 		case CISS_LD_EXPND:
1209 		case CISS_LD_QEXPND:
1210 		case CISS_LD_RBLDRD:
1211 		case CISS_LD_REBLD:
1212 			sc->sensors[i].value = SENSOR_DRIVE_REBUILD;
1213 			sc->sensors[i].status = SENSOR_S_WARN;
1214 			break;
1215 
1216 		case CISS_LD_NORDY:
1217 		case CISS_LD_PDINV:
1218 		case CISS_LD_PDUNC:
1219 		case CISS_LD_FAILED:
1220 		case CISS_LD_UNCONF:
1221 			sc->sensors[i].value = SENSOR_DRIVE_FAIL;
1222 			sc->sensors[i].status = SENSOR_S_CRIT;
1223 			break;
1224 
1225 		default:
1226 			sc->sensors[i].value = 0;
1227 			sc->sensors[i].status = SENSOR_S_UNKNOWN;
1228 		}
1229 	}
1230 }
1231 #endif /* SMALL_KERNEL */
1232 
1233 int
1234 ciss_ldid(struct ciss_softc *sc, int target, struct ciss_ldid *id)
1235 {
1236 	struct ciss_ccb *ccb;
1237 	struct ciss_cmd *cmd;
1238 
1239 	ccb = ciss_get_ccb(sc);
1240 	if (ccb == NULL)
1241 		return ENOMEM;
1242 	ccb->ccb_len = sizeof(*id);
1243 	ccb->ccb_data = id;
1244 	ccb->ccb_xs = NULL;
1245 	cmd = &ccb->ccb_cmd;
1246 	cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
1247 	cmd->tgt2 = 0;
1248 	cmd->cdblen = 10;
1249 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
1250 	cmd->tmo = htole16(0);
1251 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
1252 	cmd->cdb[0] = CISS_CMD_CTRL_GET;
1253 	cmd->cdb[5] = target;
1254 	cmd->cdb[6] = CISS_CMS_CTRL_LDIDEXT;
1255 	cmd->cdb[7] = sizeof(*id) >> 8;	/* biiiig endian */
1256 	cmd->cdb[8] = sizeof(*id) & 0xff;
1257 
1258 	return ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
1259 }
1260 
1261 int
1262 ciss_ldstat(struct ciss_softc *sc, int target, struct ciss_ldstat *stat)
1263 {
1264 	struct ciss_ccb *ccb;
1265 	struct ciss_cmd *cmd;
1266 
1267 	ccb = ciss_get_ccb(sc);
1268 	if (ccb == NULL)
1269 		return ENOMEM;
1270 	ccb->ccb_len = sizeof(*stat);
1271 	ccb->ccb_data = stat;
1272 	ccb->ccb_xs = NULL;
1273 	cmd = &ccb->ccb_cmd;
1274 	cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
1275 	cmd->tgt2 = 0;
1276 	cmd->cdblen = 10;
1277 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
1278 	cmd->tmo = htole16(0);
1279 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
1280 	cmd->cdb[0] = CISS_CMD_CTRL_GET;
1281 	cmd->cdb[5] = target;
1282 	cmd->cdb[6] = CISS_CMS_CTRL_LDSTAT;
1283 	cmd->cdb[7] = sizeof(*stat) >> 8;	/* biiiig endian */
1284 	cmd->cdb[8] = sizeof(*stat) & 0xff;
1285 
1286 	return ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
1287 }
1288 
1289 int
1290 ciss_pdid(struct ciss_softc *sc, u_int8_t drv, struct ciss_pdid *id, int wait)
1291 {
1292 	struct ciss_ccb *ccb;
1293 	struct ciss_cmd *cmd;
1294 
1295 	ccb = ciss_get_ccb(sc);
1296 	if (ccb == NULL)
1297 		return ENOMEM;
1298 	ccb->ccb_len = sizeof(*id);
1299 	ccb->ccb_data = id;
1300 	ccb->ccb_xs = NULL;
1301 	cmd = &ccb->ccb_cmd;
1302 	cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
1303 	cmd->tgt2 = 0;
1304 	cmd->cdblen = 10;
1305 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
1306 	cmd->tmo = htole16(0);
1307 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
1308 	cmd->cdb[0] = CISS_CMD_CTRL_GET;
1309 	cmd->cdb[2] = drv;
1310 	cmd->cdb[6] = CISS_CMS_CTRL_PDID;
1311 	cmd->cdb[7] = sizeof(*id) >> 8;	/* biiiig endian */
1312 	cmd->cdb[8] = sizeof(*id) & 0xff;
1313 
1314 	return ciss_cmd(ccb, BUS_DMA_NOWAIT, wait);
1315 }
1316 
1317 
1318 struct ciss_ld *
1319 ciss_pdscan(struct ciss_softc *sc, int ld)
1320 {
1321 	struct ciss_pdid *pdid;
1322 	struct ciss_ld *ldp;
1323 	u_int8_t drv, buf[128];
1324 	int i, j, k = 0;
1325 
1326 	pdid = sc->scratch;
1327 	if (sc->ndrives == 256) {
1328 		for (i = 0; i < CISS_BIGBIT; i++)
1329 			if (!ciss_pdid(sc, i, pdid, SCSI_NOSLEEP|SCSI_POLL) &&
1330 			    (pdid->present & CISS_PD_PRESENT))
1331 				buf[k++] = i;
1332 	} else
1333 		for (i = 0; i < sc->nbus; i++)
1334 			for (j = 0; j < sc->ndrives; j++) {
1335 				drv = CISS_BIGBIT + i * sc->ndrives + j;
1336 				if (!ciss_pdid(sc, drv, pdid,
1337 				    SCSI_NOSLEEP|SCSI_POLL))
1338 					buf[k++] = drv;
1339 			}
1340 
1341 	if (!k)
1342 		return NULL;
1343 
1344 	ldp = malloc(sizeof(*ldp) + (k-1), M_DEVBUF, M_NOWAIT);
1345 	if (!ldp)
1346 		return NULL;
1347 
1348 	bzero(&ldp->bling, sizeof(ldp->bling));
1349 	ldp->ndrives = k;
1350 	bcopy(buf, ldp->tgts, k);
1351 	return ldp;
1352 }
1353 
1354 int
1355 ciss_blink(struct ciss_softc *sc, int ld, int pd, int stat,
1356     struct ciss_blink *blink)
1357 {
1358 	struct ciss_ccb *ccb;
1359 	struct ciss_cmd *cmd;
1360 	struct ciss_ld *ldp;
1361 
1362 	if (ld > sc->maxunits)
1363 		return EINVAL;
1364 
1365 	ldp = sc->sc_lds[ld];
1366 	if (!ldp || pd > ldp->ndrives)
1367 		return EINVAL;
1368 
1369 	ldp->bling.pdtab[ldp->tgts[pd]] = stat == BIOC_SBUNBLINK? 0 :
1370 	    CISS_BLINK_ALL;
1371 	bcopy(&ldp->bling, blink, sizeof(*blink));
1372 
1373 	ccb = ciss_get_ccb(sc);
1374 	if (ccb == NULL)
1375 		return ENOMEM;
1376 	ccb->ccb_len = sizeof(*blink);
1377 	ccb->ccb_data = blink;
1378 	ccb->ccb_xs = NULL;
1379 	cmd = &ccb->ccb_cmd;
1380 	cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
1381 	cmd->tgt2 = 0;
1382 	cmd->cdblen = 10;
1383 	cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_OUT;
1384 	cmd->tmo = htole16(0);
1385 	bzero(&cmd->cdb[0], sizeof(cmd->cdb));
1386 	cmd->cdb[0] = CISS_CMD_CTRL_SET;
1387 	cmd->cdb[6] = CISS_CMS_CTRL_PDBLINK;
1388 	cmd->cdb[7] = sizeof(*blink) >> 8;	/* biiiig endian */
1389 	cmd->cdb[8] = sizeof(*blink) & 0xff;
1390 
1391 	return ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
1392 }
1393 #endif
1394