Annotation of sys/dev/ic/ciss.c, Revision 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