Annotation of sys/dev/ic/ciss.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: ciss.c,v 1.27 2007/06/24 05:34:35 dlg 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);
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;
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(&sc->sc_hb, hz * 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))) {
354: bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
355: bus_dmamap_destroy(sc->dmat, sc->cmdmap);
356: return -1;
357: }
358: bzero(sc->sc_lds, sc->maxunits * sizeof(*sc->sc_lds));
359:
360: sc->sc_flush = CISS_FLUSH_ENABLE;
361: if (!(sc->sc_sh = shutdownhook_establish(ciss_shutdown, sc))) {
362: printf(": unable to establish shutdown hook\n");
363: bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
364: bus_dmamap_destroy(sc->dmat, sc->cmdmap);
365: return -1;
366: }
367:
368: #if 0
369: if (kthread_create(ciss_kthread, sc, NULL, "%s", sc->sc_dev.dv_xname)) {
370: printf(": unable to create kernel thread\n");
371: shutdownhook_disestablish(sc->sc_sh);
372: bus_dmamem_free(sc->dmat, sc->cmdseg, 1);
373: bus_dmamap_destroy(sc->dmat, sc->cmdmap);
374: return -1;
375: }
376: #endif
377:
378: sc->sc_link.device = &ciss_dev;
379: sc->sc_link.adapter_softc = sc;
380: sc->sc_link.openings = sc->maxcmd / (sc->maxunits? sc->maxunits : 1);
381: #if NBIO > 0
382: /* XXX Reserve some ccb's for sensor and bioctl. */
383: if (sc->maxunits < 2 && sc->sc_link.openings > 2)
384: sc->sc_link.openings -= 2;
385: #endif
386: sc->sc_link.adapter = &ciss_switch;
387: sc->sc_link.adapter_target = sc->maxunits;
388: sc->sc_link.adapter_buswidth = sc->maxunits;
389: bzero(&saa, sizeof(saa));
390: saa.saa_sc_link = &sc->sc_link;
391: scsibus = (struct scsibus_softc *)config_found_sm(&sc->sc_dev,
392: &saa, scsiprint, NULL);
393:
394: #if 0
395: sc->sc_link_raw.device = &ciss_raw_dev;
396: sc->sc_link_raw.adapter_softc = sc;
397: sc->sc_link.openings = sc->maxcmd / (sc->maxunits? sc->maxunits : 1);
398: sc->sc_link_raw.adapter = &ciss_raw_switch;
399: sc->sc_link_raw.adapter_target = sc->ndrives;
400: sc->sc_link_raw.adapter_buswidth = sc->ndrives;
401: bzero(&saa, sizeof(saa));
402: saa.saa_sc_link = &sc->sc_link_raw;
403: rawbus = (struct scsibus_softc *)config_found_sm(&sc->sc_dev,
404: &saa, scsiprint, NULL);
405: #endif
406:
407: #if NBIO > 0
408: /* XXX for now we can only deal w/ one volume and need reserved ccbs. */
409: if (!scsibus || sc->maxunits > 1 || sc->sc_link.openings == sc->maxcmd)
410: return 0;
411:
412: /* now map all the physdevs into their lds */
413: /* XXX currently we assign all pf 'em into ld#0 */
414: for (i = 0; i < sc->maxunits; i++)
415: if (!(sc->sc_lds[i] = ciss_pdscan(sc, i)))
416: return 0;
417:
418: if (bio_register(&sc->sc_dev, ciss_ioctl) != 0)
419: printf("%s: controller registration failed",
420: sc->sc_dev.dv_xname);
421:
422: sc->sc_flags |= CISS_BIO;
423: #ifndef SMALL_KERNEL
424: sc->sensors = malloc(sizeof(struct ksensor) * sc->maxunits,
425: M_DEVBUF, M_NOWAIT);
426: if (sc->sensors) {
427: bzero(sc->sensors, sizeof(struct ksensor) * sc->maxunits);
428: strlcpy(sc->sensordev.xname, sc->sc_dev.dv_xname,
429: sizeof(sc->sensordev.xname));
430: for (i = 0; i < sc->maxunits;
431: sensor_attach(&sc->sensordev, &sc->sensors[i++])) {
432: sc->sensors[i].type = SENSOR_DRIVE;
433: sc->sensors[i].status = SENSOR_S_UNKNOWN;
434: strlcpy(sc->sensors[i].desc, ((struct device *)
435: scsibus->sc_link[i][0]->device_softc)->dv_xname,
436: sizeof(sc->sensors[i].desc));
437: strlcpy(sc->sc_lds[i]->xname, ((struct device *)
438: scsibus->sc_link[i][0]->device_softc)->dv_xname,
439: sizeof(sc->sc_lds[i]->xname));
440: }
441: if (sensor_task_register(sc, ciss_sensors, 10) == NULL)
442: free(sc->sensors, M_DEVBUF);
443: else
444: sensordev_install(&sc->sensordev);
445: }
446: #endif /* SMALL_KERNEL */
447: #endif /* BIO > 0 */
448:
449: return 0;
450: }
451:
452: void
453: ciss_shutdown(void *v)
454: {
455: struct ciss_softc *sc = v;
456:
457: sc->sc_flush = CISS_FLUSH_DISABLE;
458: timeout_del(&sc->sc_hb);
459: ciss_sync(sc);
460: }
461:
462: void
463: cissminphys(struct buf *bp)
464: {
465: #if 0 /* TODO */
466: #define CISS_MAXFER (PAGE_SIZE * (sc->maxsg + 1))
467: if (bp->b_bcount > CISS_MAXFER)
468: bp->b_bcount = CISS_MAXFER;
469: #endif
470: minphys(bp);
471: }
472:
473: /*
474: * submit a command and optionally wait for completition.
475: * wait arg abuses SCSI_POLL|SCSI_NOSLEEP flags to request
476: * to wait (SCSI_POLL) and to allow tsleep() (!SCSI_NOSLEEP)
477: * instead of busy loop waiting
478: */
479: int
480: ciss_cmd(struct ciss_ccb *ccb, int flags, int wait)
481: {
482: struct ciss_softc *sc = ccb->ccb_sc;
483: struct ciss_cmd *cmd = &ccb->ccb_cmd;
484: struct ciss_ccb *ccb1;
485: bus_dmamap_t dmap = ccb->ccb_dmamap;
486: u_int32_t id;
487: int i, tohz, error = 0;
488:
489: if (ccb->ccb_state != CISS_CCB_READY) {
490: printf("%s: ccb %d not ready state=%b\n", sc->sc_dev.dv_xname,
491: cmd->id, ccb->ccb_state, CISS_CCB_BITS);
492: return (EINVAL);
493: }
494:
495: if (ccb->ccb_data) {
496: bus_dma_segment_t *sgd;
497:
498: if ((error = bus_dmamap_load(sc->dmat, dmap, ccb->ccb_data,
499: ccb->ccb_len, NULL, flags))) {
500: if (error == EFBIG)
501: printf("more than %d dma segs\n", sc->maxsg);
502: else
503: printf("error %d loading dma map\n", error);
504: ciss_put_ccb(ccb);
505: return (error);
506: }
507: cmd->sgin = dmap->dm_nsegs;
508:
509: sgd = dmap->dm_segs;
510: CISS_DPRINTF(CISS_D_DMA, ("data=%p/%u<0x%lx/%u",
511: ccb->ccb_data, ccb->ccb_len, sgd->ds_addr, sgd->ds_len));
512:
513: for (i = 0; i < dmap->dm_nsegs; sgd++, i++) {
514: cmd->sgl[i].addr_lo = htole32(sgd->ds_addr);
515: cmd->sgl[i].addr_hi =
516: htole32((u_int64_t)sgd->ds_addr >> 32);
517: cmd->sgl[i].len = htole32(sgd->ds_len);
518: cmd->sgl[i].flags = htole32(0);
519: if (i)
520: CISS_DPRINTF(CISS_D_DMA,
521: (",0x%lx/%u", sgd->ds_addr, sgd->ds_len));
522: }
523:
524: CISS_DPRINTF(CISS_D_DMA, ("> "));
525:
526: bus_dmamap_sync(sc->dmat, dmap, 0, dmap->dm_mapsize,
527: BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
528: } else
529: cmd->sgin = 0;
530: cmd->sglen = htole16((u_int16_t)cmd->sgin);
531: bzero(&ccb->ccb_err, sizeof(ccb->ccb_err));
532:
533: bus_dmamap_sync(sc->dmat, sc->cmdmap, 0, sc->cmdmap->dm_mapsize,
534: BUS_DMASYNC_PREWRITE);
535:
536: if ((wait & (SCSI_POLL|SCSI_NOSLEEP)) == (SCSI_POLL|SCSI_NOSLEEP))
537: bus_space_write_4(sc->iot, sc->ioh, CISS_IMR,
538: bus_space_read_4(sc->iot, sc->ioh, CISS_IMR) | sc->iem);
539:
540: TAILQ_INSERT_TAIL(&sc->sc_ccbq, ccb, ccb_link);
541: ccb->ccb_state = CISS_CCB_ONQ;
542: CISS_DPRINTF(CISS_D_CMD, ("submit=0x%x ", cmd->id));
543: bus_space_write_4(sc->iot, sc->ioh, CISS_INQ, ccb->ccb_cmdpa);
544:
545: if (wait & SCSI_POLL) {
546: struct timeval tv;
547: int etick;
548: CISS_DPRINTF(CISS_D_CMD, ("waiting "));
549:
550: i = ccb->ccb_xs? ccb->ccb_xs->timeout : 60000;
551: tv.tv_sec = i / 1000;
552: tv.tv_usec = (i % 1000) * 1000;
553: tohz = tvtohz(&tv);
554: if (tohz == 0)
555: tohz = 1;
556: for (i *= 100, etick = tick + tohz; i--; ) {
557: if (!(wait & SCSI_NOSLEEP)) {
558: ccb->ccb_state = CISS_CCB_POLL;
559: CISS_DPRINTF(CISS_D_CMD, ("tsleep(%d) ", tohz));
560: if (tsleep(ccb, PRIBIO + 1, "ciss_cmd",
561: tohz) == EWOULDBLOCK) {
562: break;
563: }
564: if (ccb->ccb_state != CISS_CCB_ONQ) {
565: tohz = etick - tick;
566: if (tohz <= 0)
567: break;
568: CISS_DPRINTF(CISS_D_CMD, ("T"));
569: continue;
570: }
571: ccb1 = ccb;
572: } else {
573: DELAY(10);
574:
575: if (!(bus_space_read_4(sc->iot, sc->ioh,
576: CISS_ISR) & sc->iem)) {
577: CISS_DPRINTF(CISS_D_CMD, ("N"));
578: continue;
579: }
580:
581: if ((id = bus_space_read_4(sc->iot, sc->ioh,
582: CISS_OUTQ)) == 0xffffffff) {
583: CISS_DPRINTF(CISS_D_CMD, ("Q"));
584: continue;
585: }
586:
587: CISS_DPRINTF(CISS_D_CMD, ("got=0x%x ", id));
588: ccb1 = sc->ccbs + (id >> 2) * sc->ccblen;
589: ccb1->ccb_cmd.id = htole32(id);
590: }
591:
592: error = ciss_done(ccb1);
593: if (ccb1 == ccb)
594: break;
595: }
596:
597: /* if never got a chance to be done above... */
598: if (ccb->ccb_state != CISS_CCB_FREE) {
599: ccb->ccb_err.cmd_stat = CISS_ERR_TMO;
600: error = ciss_done(ccb);
601: }
602:
603: CISS_DPRINTF(CISS_D_CMD, ("done %d:%d",
604: ccb->ccb_err.cmd_stat, ccb->ccb_err.scsi_stat));
605: }
606:
607: if ((wait & (SCSI_POLL|SCSI_NOSLEEP)) == (SCSI_POLL|SCSI_NOSLEEP))
608: bus_space_write_4(sc->iot, sc->ioh, CISS_IMR,
609: bus_space_read_4(sc->iot, sc->ioh, CISS_IMR) & ~sc->iem);
610:
611: return (error);
612: }
613:
614: int
615: ciss_done(struct ciss_ccb *ccb)
616: {
617: struct ciss_softc *sc = ccb->ccb_sc;
618: struct scsi_xfer *xs = ccb->ccb_xs;
619: ciss_lock_t lock;
620: int error = 0;
621:
622: CISS_DPRINTF(CISS_D_CMD, ("ciss_done(%p) ", ccb));
623:
624: if (ccb->ccb_state != CISS_CCB_ONQ) {
625: printf("%s: unqueued ccb %p ready, state=%b\n",
626: sc->sc_dev.dv_xname, ccb, ccb->ccb_state, CISS_CCB_BITS);
627: return 1;
628: }
629:
630: lock = CISS_LOCK(sc);
631: ccb->ccb_state = CISS_CCB_READY;
632: TAILQ_REMOVE(&sc->sc_ccbq, ccb, ccb_link);
633:
634: if (ccb->ccb_cmd.id & CISS_CMD_ERR)
635: error = ciss_error(ccb);
636:
637: if (ccb->ccb_data) {
638: bus_dmamap_sync(sc->dmat, ccb->ccb_dmamap, 0,
639: ccb->ccb_dmamap->dm_mapsize, (xs->flags & SCSI_DATA_IN) ?
640: BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
641: bus_dmamap_unload(sc->dmat, ccb->ccb_dmamap);
642: ccb->ccb_xs = NULL;
643: ccb->ccb_data = NULL;
644: }
645:
646: ciss_put_ccb(ccb);
647:
648: if (xs) {
649: xs->resid = 0;
650: xs->flags |= ITSDONE;
651: CISS_DPRINTF(CISS_D_CMD, ("scsi_done(%p) ", xs));
652: scsi_done(xs);
653: }
654: CISS_UNLOCK(sc, lock);
655:
656: return error;
657: }
658:
659: int
660: ciss_error(struct ciss_ccb *ccb)
661: {
662: struct ciss_softc *sc = ccb->ccb_sc;
663: struct ciss_error *err = &ccb->ccb_err;
664: struct scsi_xfer *xs = ccb->ccb_xs;
665: int rv;
666:
667: switch ((rv = letoh16(err->cmd_stat))) {
668: case CISS_ERR_OK:
669: rv = 0;
670: break;
671:
672: case CISS_ERR_INVCMD:
673: printf("%s: invalid cmd 0x%x: 0x%x is not valid @ 0x%x[%d]\n",
674: sc->sc_dev.dv_xname, ccb->ccb_cmd.id,
675: err->err_info, err->err_type[3], err->err_type[2]);
676: if (xs) {
677: bzero(&xs->sense, sizeof(xs->sense));
678: xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
679: xs->sense.flags = SKEY_ILLEGAL_REQUEST;
680: xs->sense.add_sense_code = 0x24; /* ill field */
681: xs->error = XS_SENSE;
682: }
683: rv = EIO;
684: break;
685:
686: case CISS_ERR_TMO:
687: xs->error = XS_TIMEOUT;
688: rv = ETIMEDOUT;
689: break;
690:
691: default:
692: if (xs) {
693: switch (err->scsi_stat) {
694: case SCSI_CHECK:
695: xs->error = XS_SENSE;
696: bcopy(&err->sense[0], &xs->sense,
697: sizeof(xs->sense));
698: rv = EIO;
699: break;
700:
701: case SCSI_BUSY:
702: xs->error = XS_BUSY;
703: rv = EBUSY;
704: break;
705:
706: default:
707: CISS_DPRINTF(CISS_D_ERR, ("%s: "
708: "cmd_stat %x scsi_stat 0x%x\n",
709: sc->sc_dev.dv_xname, rv, err->scsi_stat));
710: xs->error = XS_DRIVER_STUFFUP;
711: rv = EIO;
712: break;
713: }
714: xs->resid = letoh32(err->resid);
715: } else
716: rv = EIO;
717: }
718: ccb->ccb_cmd.id &= htole32(~3);
719:
720: return rv;
721: }
722:
723: int
724: ciss_inq(struct ciss_softc *sc, struct ciss_inquiry *inq)
725: {
726: struct ciss_ccb *ccb;
727: struct ciss_cmd *cmd;
728:
729: ccb = ciss_get_ccb(sc);
730: ccb->ccb_len = sizeof(*inq);
731: ccb->ccb_data = inq;
732: cmd = &ccb->ccb_cmd;
733: cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
734: cmd->tgt2 = 0;
735: cmd->cdblen = 10;
736: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
737: cmd->tmo = htole16(0);
738: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
739: cmd->cdb[0] = CISS_CMD_CTRL_GET;
740: cmd->cdb[6] = CISS_CMS_CTRL_CTRL;
741: cmd->cdb[7] = sizeof(*inq) >> 8; /* biiiig endian */
742: cmd->cdb[8] = sizeof(*inq) & 0xff;
743:
744: return ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
745: }
746:
747: int
748: ciss_ldmap(struct ciss_softc *sc)
749: {
750: struct ciss_ccb *ccb;
751: struct ciss_cmd *cmd;
752: struct ciss_ldmap *lmap;
753: ciss_lock_t lock;
754: int total, rv;
755:
756: lock = CISS_LOCK_SCRATCH(sc);
757: lmap = sc->scratch;
758: lmap->size = htobe32(sc->maxunits * sizeof(lmap->map));
759: total = sizeof(*lmap) + (sc->maxunits - 1) * sizeof(lmap->map);
760:
761: ccb = ciss_get_ccb(sc);
762: ccb->ccb_len = total;
763: ccb->ccb_data = lmap;
764: cmd = &ccb->ccb_cmd;
765: cmd->tgt = CISS_CMD_MODE_PERIPH;
766: cmd->tgt2 = 0;
767: cmd->cdblen = 12;
768: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
769: cmd->tmo = htole16(30);
770: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
771: cmd->cdb[0] = CISS_CMD_LDMAP;
772: cmd->cdb[8] = total >> 8; /* biiiig endian */
773: cmd->cdb[9] = total & 0xff;
774:
775: rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
776: CISS_UNLOCK_SCRATCH(sc, lock);
777:
778: if (rv)
779: return rv;
780:
781: CISS_DPRINTF(CISS_D_MISC, ("lmap %x:%x\n",
782: lmap->map[0].tgt, lmap->map[0].tgt2));
783:
784: return 0;
785: }
786:
787: int
788: ciss_sync(struct ciss_softc *sc)
789: {
790: struct ciss_ccb *ccb;
791: struct ciss_cmd *cmd;
792: struct ciss_flush *flush;
793: ciss_lock_t lock;
794: int rv;
795:
796: lock = CISS_LOCK_SCRATCH(sc);
797: flush = sc->scratch;
798: bzero(flush, sizeof(*flush));
799: flush->flush = sc->sc_flush;
800:
801: ccb = ciss_get_ccb(sc);
802: ccb->ccb_len = sizeof(*flush);
803: ccb->ccb_data = flush;
804: cmd = &ccb->ccb_cmd;
805: cmd->tgt = CISS_CMD_MODE_PERIPH;
806: cmd->tgt2 = 0;
807: cmd->cdblen = 10;
808: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_OUT;
809: cmd->tmo = htole16(0);
810: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
811: cmd->cdb[0] = CISS_CMD_CTRL_SET;
812: cmd->cdb[6] = CISS_CMS_CTRL_FLUSH;
813: cmd->cdb[7] = sizeof(*flush) >> 8; /* biiiig endian */
814: cmd->cdb[8] = sizeof(*flush) & 0xff;
815:
816: rv = ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL|SCSI_NOSLEEP);
817: CISS_UNLOCK_SCRATCH(sc, lock);
818:
819: return rv;
820: }
821:
822: int
823: ciss_scsi_raw_cmd(struct scsi_xfer *xs) /* TODO */
824: {
825: struct scsi_link *link = xs->sc_link;
826: struct ciss_rawsoftc *rsc = link->adapter_softc;
827: struct ciss_softc *sc = rsc->sc_softc;
828: struct ciss_ccb *ccb;
829: struct ciss_cmd *cmd;
830: ciss_lock_t lock;
831: int error;
832:
833: CISS_DPRINTF(CISS_D_CMD, ("ciss_scsi_raw_cmd "));
834:
835: if (xs->cmdlen > CISS_MAX_CDB) {
836: CISS_DPRINTF(CISS_D_CMD, ("CDB too big %p ", xs));
837: bzero(&xs->sense, sizeof(xs->sense));
838: xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
839: xs->sense.flags = SKEY_ILLEGAL_REQUEST;
840: xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
841: xs->error = XS_SENSE;
842: scsi_done(xs);
843: return (COMPLETE);
844: }
845:
846: lock = CISS_LOCK(sc);
847: error = 0;
848: xs->error = XS_NOERROR;
849:
850: /* TODO check this target has not yet employed w/ any volume */
851:
852: ccb = ciss_get_ccb(sc);
853: cmd = &ccb->ccb_cmd;
854: ccb->ccb_len = xs->datalen;
855: ccb->ccb_data = xs->data;
856: ccb->ccb_xs = xs;
857:
858:
859:
860: cmd->cdblen = xs->cmdlen;
861: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL;
862: if (xs->flags & SCSI_DATA_IN)
863: cmd->flags |= CISS_CDB_IN;
864: else if (xs->flags & SCSI_DATA_OUT)
865: cmd->flags |= CISS_CDB_OUT;
866: cmd->tmo = htole16(xs->timeout < 1000? 1 : xs->timeout / 1000);
867: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
868: bcopy(xs->cmd, &cmd->cdb[0], CISS_MAX_CDB);
869:
870: if (ciss_cmd(ccb, BUS_DMA_WAITOK,
871: xs->flags & (SCSI_POLL|SCSI_NOSLEEP))) {
872: xs->error = XS_DRIVER_STUFFUP;
873: scsi_done(xs);
874: CISS_UNLOCK(sc, lock);
875: return (COMPLETE);
876: }
877:
878: CISS_UNLOCK(sc, lock);
879: return xs->flags & SCSI_POLL? COMPLETE : SUCCESSFULLY_QUEUED;
880: }
881:
882: int
883: ciss_scsi_cmd(struct scsi_xfer *xs)
884: {
885: struct scsi_link *link = xs->sc_link;
886: struct ciss_softc *sc = link->adapter_softc;
887: u_int8_t target = link->target;
888: struct ciss_ccb *ccb;
889: struct ciss_cmd *cmd;
890: int error;
891: ciss_lock_t lock;
892:
893: CISS_DPRINTF(CISS_D_CMD, ("ciss_scsi_cmd "));
894:
895: if (xs->cmdlen > CISS_MAX_CDB) {
896: CISS_DPRINTF(CISS_D_CMD, ("CDB too big %p ", xs));
897: bzero(&xs->sense, sizeof(xs->sense));
898: xs->sense.error_code = SSD_ERRCODE_VALID | 0x70;
899: xs->sense.flags = SKEY_ILLEGAL_REQUEST;
900: xs->sense.add_sense_code = 0x20; /* illcmd, 0x24 illfield */
901: xs->error = XS_SENSE;
902: scsi_done(xs);
903: return (COMPLETE);
904: }
905:
906: lock = CISS_LOCK(sc);
907: error = 0;
908: xs->error = XS_NOERROR;
909:
910: /* XXX emulate SYNCHRONIZE_CACHE ??? */
911:
912: ccb = ciss_get_ccb(sc);
913: cmd = &ccb->ccb_cmd;
914: ccb->ccb_len = xs->datalen;
915: ccb->ccb_data = xs->data;
916: ccb->ccb_xs = xs;
917: cmd->tgt = CISS_CMD_MODE_LD | target;
918: cmd->tgt2 = 0;
919: cmd->cdblen = xs->cmdlen;
920: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL;
921: if (xs->flags & SCSI_DATA_IN)
922: cmd->flags |= CISS_CDB_IN;
923: else if (xs->flags & SCSI_DATA_OUT)
924: cmd->flags |= CISS_CDB_OUT;
925: cmd->tmo = htole16(xs->timeout < 1000? 1 : xs->timeout / 1000);
926: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
927: bcopy(xs->cmd, &cmd->cdb[0], CISS_MAX_CDB);
928:
929: if (ciss_cmd(ccb, BUS_DMA_WAITOK,
930: xs->flags & (SCSI_POLL|SCSI_NOSLEEP))) {
931: xs->error = XS_DRIVER_STUFFUP;
932: scsi_done(xs);
933: CISS_UNLOCK(sc, lock);
934: return (COMPLETE);
935: }
936:
937: CISS_UNLOCK(sc, lock);
938: return xs->flags & SCSI_POLL? COMPLETE : SUCCESSFULLY_QUEUED;
939: }
940:
941: int
942: ciss_intr(void *v)
943: {
944: struct ciss_softc *sc = v;
945: struct ciss_ccb *ccb;
946: ciss_lock_t lock;
947: u_int32_t id;
948: int hit = 0;
949:
950: CISS_DPRINTF(CISS_D_INTR, ("intr "));
951:
952: if (!(bus_space_read_4(sc->iot, sc->ioh, CISS_ISR) & sc->iem))
953: return 0;
954:
955: lock = CISS_LOCK(sc);
956: while ((id = bus_space_read_4(sc->iot, sc->ioh, CISS_OUTQ)) !=
957: 0xffffffff) {
958:
959: ccb = sc->ccbs + (id >> 2) * sc->ccblen;
960: ccb->ccb_cmd.id = htole32(id);
961: if (ccb->ccb_state == CISS_CCB_POLL) {
962: ccb->ccb_state = CISS_CCB_ONQ;
963: wakeup(ccb);
964: } else
965: ciss_done(ccb);
966:
967: hit = 1;
968: }
969: CISS_UNLOCK(sc, lock);
970:
971: CISS_DPRINTF(CISS_D_INTR, ("exit "));
972: return hit;
973: }
974:
975: void
976: ciss_heartbeat(void *v)
977: {
978: struct ciss_softc *sc = v;
979: u_int32_t hb;
980:
981: hb = bus_space_read_4(sc->iot, sc->cfg_ioh,
982: sc->cfgoff + offsetof(struct ciss_config, heartbeat));
983: if (hb == sc->heartbeat)
984: panic("%s: dead", sc->sc_dev.dv_xname); /* XXX reset! */
985: else
986: sc->heartbeat = hb;
987:
988: timeout_add(&sc->sc_hb, hz * 3);
989: }
990:
991: void
992: ciss_kthread(void *v)
993: {
994: struct ciss_softc *sc = v;
995: ciss_lock_t lock;
996:
997: for (;;) {
998: tsleep(sc, PRIBIO, sc->sc_dev.dv_xname, 0);
999:
1000: lock = CISS_LOCK(sc);
1001:
1002:
1003:
1004: CISS_UNLOCK(sc, lock);
1005: }
1006: }
1007:
1008: int
1009: ciss_scsi_ioctl(struct scsi_link *link, u_long cmd,
1010: caddr_t addr, int flag, struct proc *p)
1011: {
1012: #if NBIO > 0
1013: return ciss_ioctl(link->adapter_softc, cmd, addr);
1014: #else
1015: return ENOTTY;
1016: #endif
1017: }
1018:
1019: #if NBIO > 0
1020: const int ciss_level[] = { 0, 4, 1, 5, 51, 7 };
1021: const int ciss_stat[] = { BIOC_SVONLINE, BIOC_SVOFFLINE, BIOC_SVOFFLINE,
1022: BIOC_SVDEGRADED, BIOC_SVREBUILD, BIOC_SVREBUILD, BIOC_SVDEGRADED,
1023: BIOC_SVDEGRADED, BIOC_SVINVALID, BIOC_SVINVALID, BIOC_SVBUILDING,
1024: BIOC_SVOFFLINE, BIOC_SVBUILDING };
1025:
1026: int
1027: ciss_ioctl(struct device *dev, u_long cmd, caddr_t addr)
1028: {
1029: struct ciss_softc *sc = (struct ciss_softc *)dev;
1030: struct bioc_inq *bi;
1031: struct bioc_vol *bv;
1032: struct bioc_disk *bd;
1033: struct bioc_blink *bb;
1034: /* struct bioc_alarm *ba; */
1035: /* struct bioc_setstate *bss; */
1036: struct ciss_ldid *ldid;
1037: struct ciss_ldstat *ldstat;
1038: struct ciss_pdid *pdid;
1039: struct ciss_blink *blink;
1040: struct ciss_ld *ldp;
1041: ciss_lock_t lock;
1042: int ld, pd, error = 0;
1043: u_int blks;
1044:
1045: if (!(sc->sc_flags & CISS_BIO))
1046: return ENOTTY;
1047:
1048: lock = CISS_LOCK(sc);
1049: switch (cmd) {
1050: case BIOCINQ:
1051: bi = (struct bioc_inq *)addr;
1052: strlcpy(bi->bi_dev, sc->sc_dev.dv_xname, sizeof(bi->bi_dev));
1053: bi->bi_novol = sc->maxunits;
1054: bi->bi_nodisk = sc->ndrives;
1055: break;
1056:
1057: case BIOCVOL:
1058: bv = (struct bioc_vol *)addr;
1059: if (bv->bv_volid > sc->maxunits) {
1060: error = EINVAL;
1061: break;
1062: }
1063: ldp = sc->sc_lds[bv->bv_volid];
1064: if (!ldp)
1065: return EINVAL;
1066: ldid = sc->scratch;
1067: if ((error = ciss_ldid(sc, bv->bv_volid, ldid)))
1068: break;
1069: /* params 30:88:ff:00:00:00:00:00:00:00:00:00:00:00:20:00 */
1070: bv->bv_status = BIOC_SVINVALID;
1071: blks = (u_int)letoh16(ldid->nblocks[1]) << 16 |
1072: letoh16(ldid->nblocks[0]);
1073: bv->bv_size = blks * (u_quad_t)letoh16(ldid->blksize);
1074: bv->bv_level = ciss_level[ldid->type];
1075: bv->bv_nodisk = ldp->ndrives;
1076: strlcpy(bv->bv_dev, ldp->xname, sizeof(bv->bv_dev));
1077: strlcpy(bv->bv_vendor, "CISS", sizeof(bv->bv_vendor));
1078: ldstat = sc->scratch;
1079: bzero(ldstat, sizeof(*ldstat));
1080: if ((error = ciss_ldstat(sc, bv->bv_volid, ldstat)))
1081: break;
1082: bv->bv_percent = -1;
1083: bv->bv_seconds = 0;
1084: if (ldstat->stat < sizeof(ciss_stat)/sizeof(ciss_stat[0]))
1085: bv->bv_status = ciss_stat[ldstat->stat];
1086: if (bv->bv_status == BIOC_SVREBUILD ||
1087: bv->bv_status == BIOC_SVBUILDING)
1088: bv->bv_percent = (blks -
1089: (((u_int)ldstat->prog[3] << 24) |
1090: ((u_int)ldstat->prog[2] << 16) |
1091: ((u_int)ldstat->prog[1] << 8) |
1092: (u_int)ldstat->prog[0])) * 100ULL / blks;
1093: break;
1094:
1095: case BIOCDISK:
1096: bd = (struct bioc_disk *)addr;
1097: if (bd->bd_volid > sc->maxunits) {
1098: error = EINVAL;
1099: break;
1100: }
1101: ldp = sc->sc_lds[bd->bd_volid];
1102: if (!ldp || (pd = bd->bd_diskid) > ldp->ndrives) {
1103: error = EINVAL;
1104: break;
1105: }
1106: ldstat = sc->scratch;
1107: if ((error = ciss_ldstat(sc, bd->bd_volid, ldstat)))
1108: break;
1109: bd->bd_status = -1;
1110: if (ldstat->bigrebuild == ldp->tgts[pd])
1111: bd->bd_status = BIOC_SDREBUILD;
1112: if (ciss_bitset(ldp->tgts[pd] & (~CISS_BIGBIT),
1113: ldstat->bigfailed)) {
1114: bd->bd_status = BIOC_SDFAILED;
1115: bd->bd_size = 0;
1116: bd->bd_channel = (ldp->tgts[pd] & (~CISS_BIGBIT)) /
1117: sc->ndrives;
1118: bd->bd_target = ldp->tgts[pd] % sc->ndrives;
1119: bd->bd_lun = 0;
1120: bd->bd_vendor[0] = '\0';
1121: bd->bd_serial[0] = '\0';
1122: bd->bd_procdev[0] = '\0';
1123: } else {
1124: pdid = sc->scratch;
1125: if ((error = ciss_pdid(sc, ldp->tgts[pd], pdid,
1126: SCSI_POLL)))
1127: break;
1128: if (bd->bd_status < 0) {
1129: if (pdid->config & CISS_PD_SPARE)
1130: bd->bd_status = BIOC_SDHOTSPARE;
1131: else if (pdid->present & CISS_PD_PRESENT)
1132: bd->bd_status = BIOC_SDONLINE;
1133: else
1134: bd->bd_status = BIOC_SDINVALID;
1135: }
1136: bd->bd_size = (u_int64_t)letoh32(pdid->nblocks) *
1137: letoh16(pdid->blksz);
1138: bd->bd_channel = pdid->bus;
1139: bd->bd_target = pdid->target;
1140: bd->bd_lun = 0;
1141: strlcpy(bd->bd_vendor, pdid->model,
1142: sizeof(bd->bd_vendor));
1143: strlcpy(bd->bd_serial, pdid->serial,
1144: sizeof(bd->bd_serial));
1145: bd->bd_procdev[0] = '\0';
1146: }
1147: break;
1148:
1149: case BIOCBLINK:
1150: bb = (struct bioc_blink *)addr;
1151: blink = sc->scratch;
1152: error = EINVAL;
1153: /* XXX workaround completely dumb scsi addressing */
1154: for (ld = 0; ld < sc->maxunits; ld++) {
1155: ldp = sc->sc_lds[ld];
1156: if (!ldp)
1157: continue;
1158: for (pd = 0; pd < ldp->ndrives; pd++)
1159: if (ldp->tgts[pd] == (CISS_BIGBIT +
1160: bb->bb_channel * sc->ndrives +
1161: bb->bb_target))
1162: error = ciss_blink(sc, ld, pd,
1163: bb->bb_status, blink);
1164: }
1165: break;
1166:
1167: case BIOCALARM:
1168: case BIOCSETSTATE:
1169: default:
1170: CISS_DPRINTF(CISS_D_IOCTL, ("%s: invalid ioctl\n",
1171: sc->sc_dev.dv_xname));
1172: error = ENOTTY;
1173: }
1174: CISS_UNLOCK(sc, lock);
1175:
1176: return error;
1177: }
1178:
1179: #ifndef SMALL_KERNEL
1180: void
1181: ciss_sensors(void *v)
1182: {
1183: struct ciss_softc *sc = v;
1184: struct ciss_ldstat *ldstat;
1185: int i, error;
1186:
1187: for (i = 0; i < sc->maxunits; i++) {
1188: ldstat = sc->scratch;
1189: if ((error = ciss_ldstat(sc, i, ldstat))) {
1190: sc->sensors[i].value = 0;
1191: sc->sensors[i].status = SENSOR_S_UNKNOWN;
1192: continue;
1193: }
1194:
1195: switch (ldstat->stat) {
1196: case CISS_LD_OK:
1197: sc->sensors[i].value = SENSOR_DRIVE_ONLINE;
1198: sc->sensors[i].status = SENSOR_S_OK;
1199: break;
1200:
1201: case CISS_LD_DEGRAD:
1202: sc->sensors[i].value = SENSOR_DRIVE_PFAIL;
1203: sc->sensors[i].status = SENSOR_S_WARN;
1204: break;
1205:
1206: case CISS_LD_EXPND:
1207: case CISS_LD_QEXPND:
1208: case CISS_LD_RBLDRD:
1209: case CISS_LD_REBLD:
1210: sc->sensors[i].value = SENSOR_DRIVE_REBUILD;
1211: sc->sensors[i].status = SENSOR_S_WARN;
1212: break;
1213:
1214: case CISS_LD_NORDY:
1215: case CISS_LD_PDINV:
1216: case CISS_LD_PDUNC:
1217: case CISS_LD_FAILED:
1218: case CISS_LD_UNCONF:
1219: sc->sensors[i].value = SENSOR_DRIVE_FAIL;
1220: sc->sensors[i].status = SENSOR_S_CRIT;
1221: break;
1222:
1223: default:
1224: sc->sensors[i].value = 0;
1225: sc->sensors[i].status = SENSOR_S_UNKNOWN;
1226: }
1227: }
1228: }
1229: #endif /* SMALL_KERNEL */
1230:
1231: int
1232: ciss_ldid(struct ciss_softc *sc, int target, struct ciss_ldid *id)
1233: {
1234: struct ciss_ccb *ccb;
1235: struct ciss_cmd *cmd;
1236:
1237: ccb = ciss_get_ccb(sc);
1238: if (ccb == NULL)
1239: return ENOMEM;
1240: ccb->ccb_len = sizeof(*id);
1241: ccb->ccb_data = id;
1242: ccb->ccb_xs = NULL;
1243: cmd = &ccb->ccb_cmd;
1244: cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
1245: cmd->tgt2 = 0;
1246: cmd->cdblen = 10;
1247: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
1248: cmd->tmo = htole16(0);
1249: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
1250: cmd->cdb[0] = CISS_CMD_CTRL_GET;
1251: cmd->cdb[5] = target;
1252: cmd->cdb[6] = CISS_CMS_CTRL_LDIDEXT;
1253: cmd->cdb[7] = sizeof(*id) >> 8; /* biiiig endian */
1254: cmd->cdb[8] = sizeof(*id) & 0xff;
1255:
1256: return ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
1257: }
1258:
1259: int
1260: ciss_ldstat(struct ciss_softc *sc, int target, struct ciss_ldstat *stat)
1261: {
1262: struct ciss_ccb *ccb;
1263: struct ciss_cmd *cmd;
1264:
1265: ccb = ciss_get_ccb(sc);
1266: if (ccb == NULL)
1267: return ENOMEM;
1268: ccb->ccb_len = sizeof(*stat);
1269: ccb->ccb_data = stat;
1270: ccb->ccb_xs = NULL;
1271: cmd = &ccb->ccb_cmd;
1272: cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
1273: cmd->tgt2 = 0;
1274: cmd->cdblen = 10;
1275: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
1276: cmd->tmo = htole16(0);
1277: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
1278: cmd->cdb[0] = CISS_CMD_CTRL_GET;
1279: cmd->cdb[5] = target;
1280: cmd->cdb[6] = CISS_CMS_CTRL_LDSTAT;
1281: cmd->cdb[7] = sizeof(*stat) >> 8; /* biiiig endian */
1282: cmd->cdb[8] = sizeof(*stat) & 0xff;
1283:
1284: return ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
1285: }
1286:
1287: int
1288: ciss_pdid(struct ciss_softc *sc, u_int8_t drv, struct ciss_pdid *id, int wait)
1289: {
1290: struct ciss_ccb *ccb;
1291: struct ciss_cmd *cmd;
1292:
1293: ccb = ciss_get_ccb(sc);
1294: if (ccb == NULL)
1295: return ENOMEM;
1296: ccb->ccb_len = sizeof(*id);
1297: ccb->ccb_data = id;
1298: ccb->ccb_xs = NULL;
1299: cmd = &ccb->ccb_cmd;
1300: cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
1301: cmd->tgt2 = 0;
1302: cmd->cdblen = 10;
1303: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_IN;
1304: cmd->tmo = htole16(0);
1305: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
1306: cmd->cdb[0] = CISS_CMD_CTRL_GET;
1307: cmd->cdb[2] = drv;
1308: cmd->cdb[6] = CISS_CMS_CTRL_PDID;
1309: cmd->cdb[7] = sizeof(*id) >> 8; /* biiiig endian */
1310: cmd->cdb[8] = sizeof(*id) & 0xff;
1311:
1312: return ciss_cmd(ccb, BUS_DMA_NOWAIT, wait);
1313: }
1314:
1315:
1316: struct ciss_ld *
1317: ciss_pdscan(struct ciss_softc *sc, int ld)
1318: {
1319: struct ciss_pdid *pdid;
1320: struct ciss_ld *ldp;
1321: u_int8_t drv, buf[128];
1322: int i, j, k = 0;
1323:
1324: pdid = sc->scratch;
1325: for (i = 0; i < sc->nbus; i++)
1326: for (j = 0; j < sc->ndrives; j++) {
1327: drv = CISS_BIGBIT + i * sc->ndrives + j;
1328: if (!ciss_pdid(sc, drv, pdid, SCSI_NOSLEEP|SCSI_POLL))
1329: buf[k++] = drv;
1330: }
1331:
1332: if (!k)
1333: return NULL;
1334:
1335: ldp = malloc(sizeof(*ldp) + (k-1), M_DEVBUF, M_NOWAIT);
1336: if (!ldp)
1337: return NULL;
1338:
1339: bzero(&ldp->bling, sizeof(ldp->bling));
1340: ldp->ndrives = k;
1341: bcopy(buf, ldp->tgts, k);
1342: return ldp;
1343: }
1344:
1345: int
1346: ciss_blink(struct ciss_softc *sc, int ld, int pd, int stat,
1347: struct ciss_blink *blink)
1348: {
1349: struct ciss_ccb *ccb;
1350: struct ciss_cmd *cmd;
1351: struct ciss_ld *ldp;
1352:
1353: if (ld > sc->maxunits)
1354: return EINVAL;
1355:
1356: ldp = sc->sc_lds[ld];
1357: if (!ldp || pd > ldp->ndrives)
1358: return EINVAL;
1359:
1360: ldp->bling.pdtab[ldp->tgts[pd]] = stat == BIOC_SBUNBLINK? 0 :
1361: CISS_BLINK_ALL;
1362: bcopy(&ldp->bling, blink, sizeof(*blink));
1363:
1364: ccb = ciss_get_ccb(sc);
1365: if (ccb == NULL)
1366: return ENOMEM;
1367: ccb->ccb_len = sizeof(*blink);
1368: ccb->ccb_data = blink;
1369: ccb->ccb_xs = NULL;
1370: cmd = &ccb->ccb_cmd;
1371: cmd->tgt = htole32(CISS_CMD_MODE_PERIPH);
1372: cmd->tgt2 = 0;
1373: cmd->cdblen = 10;
1374: cmd->flags = CISS_CDB_CMD | CISS_CDB_SIMPL | CISS_CDB_OUT;
1375: cmd->tmo = htole16(0);
1376: bzero(&cmd->cdb[0], sizeof(cmd->cdb));
1377: cmd->cdb[0] = CISS_CMD_CTRL_SET;
1378: cmd->cdb[6] = CISS_CMS_CTRL_PDBLINK;
1379: cmd->cdb[7] = sizeof(*blink) >> 8; /* biiiig endian */
1380: cmd->cdb[8] = sizeof(*blink) & 0xff;
1381:
1382: return ciss_cmd(ccb, BUS_DMA_NOWAIT, SCSI_POLL);
1383: }
1384: #endif
CVSweb