int cac_ioctl_vol(struct cac_softc *sc, struct bioc_vol *bv) { struct cac_drive_info dinfo; struct cac_drive_status dstatus; u_int32_t blks; if (bv->bv_volid > sc->sc_nunits) { return EINVAL; } if (cac_cmd(sc, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo), bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) { return EIO; } if (cac_cmd(sc, CAC_CMD_SENSE_DRV_STATUS, &dstatus, sizeof(dstatus), bv->bv_volid, 0, CAC_CCB_DATA_IN, NULL)) { return EIO; } blks = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) * CAC_GET1(dinfo.nsectors); bv->bv_size = (off_t)blks * CAC_GET2(dinfo.secsize); bv->bv_level = cac_level[CAC_GET1(dinfo.mirror)]; /*XXX limit check */ bv->bv_nodisk = 0; /* XXX */ bv->bv_status = 0; /* XXX */ bv->bv_percent = -1; bv->bv_seconds = 0; if (dstatus.stat < sizeof(cac_stat)/sizeof(cac_stat[0])) bv->bv_status = cac_stat[dstatus.stat]; if (bv->bv_status == BIOC_SVREBUILD || bv->bv_status == BIOC_SVBUILDING) bv->bv_percent = ((blks - CAC_GET4(dstatus.prog)) * 1000ULL) / blks; return 0; }
int ld_cac_start(struct ld_softc *ld, struct buf *bp) { int flags, cmd; struct cac_softc *cac; struct ld_cac_softc *sc; struct cac_context cc; sc = (struct ld_cac_softc *)ld; cac = device_private(device_parent(ld->sc_dv)); cc.cc_handler = ld_cac_done; cc.cc_context = bp; cc.cc_dv = ld->sc_dv; if ((bp->b_flags & B_READ) == 0) { cmd = CAC_CMD_WRITE; flags = CAC_CCB_DATA_OUT; } else { cmd = CAC_CMD_READ; flags = CAC_CCB_DATA_IN; } return (cac_cmd(cac, cmd, bp->b_data, bp->b_bcount, sc->sc_hwunit, bp->b_rawblkno, flags, &cc)); }
int ld_cac_dump(struct ld_softc *ld, void *data, int blkno, int blkcnt) { struct ld_cac_softc *sc; sc = (struct ld_cac_softc *)ld; return (cac_cmd(device_private(device_parent(ld->sc_dv)), CAC_CMD_WRITE_MEDIA, data, blkcnt * ld->sc_secsize, sc->sc_hwunit, blkno, CAC_CCB_DATA_OUT, NULL)); }
void ld_cac_attach(struct device *parent, struct device *self, void *aux) { struct cac_drive_info dinfo; struct cac_attach_args *caca; struct ld_softc *ld; struct ld_cac_softc *sc; struct cac_softc *cac; const char *type; sc = (struct ld_cac_softc *)self; ld = &sc->sc_ld; caca = (struct cac_attach_args *)aux; sc->sc_hwunit = caca->caca_unit; cac = (struct cac_softc *)parent; if (cac_cmd(cac, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo), sc->sc_hwunit, 0, CAC_CCB_DATA_IN, NULL)) { printf("%s: CMD_GET_LOG_DRV_INFO failed\n", self->dv_xname); return; } ld->sc_secsize = CAC_GET2(dinfo.secsize); ld->sc_maxxfer = CAC_MAX_XFER; ld->sc_maxqueuecnt = CAC_MAX_CCBS / cac->sc_nunits; /* XXX */ ld->sc_secperunit = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) * CAC_GET1(dinfo.nsectors); ld->sc_start = ld_cac_start; ld->sc_dump = ld_cac_dump; switch (CAC_GET1(dinfo.mirror)) { case 0: type = "standalone disk or RAID0"; break; case 1: type = "RAID4"; break; case 2: type = "RAID1"; break; case 3: type = "RAID5"; break; default: type = "unknown type of"; break; } printf(": %s array\n", type); /* XXX We should verify this... */ ld->sc_flags = LDF_ENABLED; ldattach(ld); }
void ld_cac_attach(device_t parent, device_t self, void *aux) { struct cac_drive_info dinfo; struct cac_attach_args *caca; struct ld_cac_softc *sc = device_private(self); struct cac_softc *cac = device_private(parent); struct ld_softc *ld = &sc->sc_ld; const char *type; caca = aux; ld->sc_dv = self; sc->sc_mutex = &cac->sc_mutex; sc->sc_hwunit = caca->caca_unit; if (cac_cmd(cac, CAC_CMD_GET_LOG_DRV_INFO, &dinfo, sizeof(dinfo), sc->sc_hwunit, 0, CAC_CCB_DATA_IN, NULL)) { aprint_error(": CMD_GET_LOG_DRV_INFO failed\n"); return; } ld->sc_secsize = CAC_GET2(dinfo.secsize); ld->sc_maxxfer = CAC_MAX_XFER; ld->sc_maxqueuecnt = (CAC_MAX_CCBS - 1) / cac->sc_nunits; ld->sc_secperunit = CAC_GET2(dinfo.ncylinders) * CAC_GET1(dinfo.nheads) * CAC_GET1(dinfo.nsectors); ld->sc_start = ld_cac_start; ld->sc_dump = ld_cac_dump; switch (CAC_GET1(dinfo.mirror)) { case 0: type = "standalone disk or RAID0"; break; case 1: type = "RAID4"; break; case 2: type = "RAID1"; break; case 3: type = "RAID5"; break; default: type = "unknown type of"; break; } aprint_normal(": %s array\n", type); /* XXX We should verify this... */ ld->sc_flags = LDF_ENABLED; ldattach(ld); }
/* * Shut down all `cac' controllers. */ static void cac_shutdown(void *cookie) { extern struct cfdriver cac_cd; struct cac_softc *sc; u_int8_t tbuf[512]; int i; for (i = 0; i < cac_cd.cd_ndevs; i++) { if ((sc = device_lookup_private(&cac_cd, i)) == NULL) continue; memset(tbuf, 0, sizeof(tbuf)); tbuf[0] = 1; cac_cmd(sc, CAC_CMD_FLUSH_CACHE, tbuf, sizeof(tbuf), 0, 0, CAC_CCB_DATA_OUT, NULL); } }
/* * Initialise our interface to the controller. */ int cac_init(struct cac_softc *sc, int startfw) { struct scsibus_attach_args saa; struct cac_controller_info cinfo; int error, rseg, size, i; bus_dma_segment_t seg[1]; struct cac_ccb *ccb; SIMPLEQ_INIT(&sc->sc_ccb_free); SIMPLEQ_INIT(&sc->sc_ccb_queue); size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) { printf("%s: unable to allocate CCBs, error = %d\n", sc->sc_dv.dv_xname, error); return (-1); } if ((error = bus_dmamem_map(sc->sc_dmat, seg, rseg, size, &sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { printf("%s: unable to map CCBs, error = %d\n", sc->sc_dv.dv_xname, error); return (-1); } if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { printf("%s: unable to create CCB DMA map, error = %d\n", sc->sc_dv.dv_xname, error); return (-1); } if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs, size, NULL, BUS_DMA_NOWAIT)) != 0) { printf("%s: unable to load CCB DMA map, error = %d\n", sc->sc_dv.dv_xname, error); return (-1); } sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; memset(sc->sc_ccbs, 0, size); ccb = (struct cac_ccb *)sc->sc_ccbs; for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) { /* Create the DMA map for this CCB's data */ error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER, CAC_SG_SIZE, CAC_MAX_XFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap_xfer); if (error) { printf("%s: can't create ccb dmamap (%d)\n", sc->sc_dv.dv_xname, error); break; } ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); } /* Start firmware background tasks, if needed. */ if (startfw) { if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo), 0, 0, CAC_CCB_DATA_IN, NULL)) { printf("%s: CAC_CMD_START_FIRMWARE failed\n", sc->sc_dv.dv_xname); return (-1); } } if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0, CAC_CCB_DATA_IN, NULL)) { printf("%s: CAC_CMD_GET_CTRL_INFO failed\n", sc->sc_dv.dv_xname); return (-1); } if (!cinfo.num_drvs) { printf("%s: no volumes defined\n", sc->sc_dv.dv_xname); return (-1); } sc->sc_nunits = cinfo.num_drvs; sc->sc_dinfos = malloc(cinfo.num_drvs * sizeof(struct cac_drive_info), M_DEVBUF, M_NOWAIT | M_ZERO); if (sc->sc_dinfos == NULL) { printf("%s: cannot allocate memory for drive_info\n", sc->sc_dv.dv_xname); return (-1); } sc->sc_link.adapter_softc = sc; sc->sc_link.adapter = &cac_switch; sc->sc_link.adapter_target = cinfo.num_drvs; sc->sc_link.adapter_buswidth = cinfo.num_drvs; sc->sc_link.device = &cac_dev; sc->sc_link.openings = CAC_MAX_CCBS / sc->sc_nunits; if (sc->sc_link.openings < 4 ) sc->sc_link.openings = 4; bzero(&saa, sizeof(saa)); saa.saa_sc_link = &sc->sc_link; config_found(&sc->sc_dv, &saa, scsiprint); /* Set our `shutdownhook' before we start any device activity. */ if (cac_sdh == NULL) cac_sdh = shutdownhook_establish(cac_shutdown, NULL); (*sc->sc_cl->cl_intr_enable)(sc, 1); return (0); }
/* * Initialise our interface to the controller. */ int cac_init(struct cac_softc *sc, const char *intrstr, int startfw) { struct cac_controller_info cinfo; int error, rseg, size, i; bus_dma_segment_t seg; struct cac_ccb *ccb; char firm[8]; if (intrstr != NULL) aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); SIMPLEQ_INIT(&sc->sc_ccb_free); SIMPLEQ_INIT(&sc->sc_ccb_queue); mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_VM); cv_init(&sc->sc_ccb_cv, "cacccb"); size = sizeof(struct cac_ccb) * CAC_MAX_CCBS; if ((error = bus_dmamem_alloc(sc->sc_dmat, size, PAGE_SIZE, 0, &seg, 1, &rseg, BUS_DMA_NOWAIT)) != 0) { aprint_error_dev(sc->sc_dev, "unable to allocate CCBs, error = %d\n", error); return (-1); } if ((error = bus_dmamem_map(sc->sc_dmat, &seg, rseg, size, (void **)&sc->sc_ccbs, BUS_DMA_NOWAIT | BUS_DMA_COHERENT)) != 0) { aprint_error_dev(sc->sc_dev, "unable to map CCBs, error = %d\n", error); return (-1); } if ((error = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0, BUS_DMA_NOWAIT, &sc->sc_dmamap)) != 0) { aprint_error_dev(sc->sc_dev, "unable to create CCB DMA map, error = %d\n", error); return (-1); } if ((error = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, sc->sc_ccbs, size, NULL, BUS_DMA_NOWAIT)) != 0) { aprint_error_dev(sc->sc_dev, "unable to load CCB DMA map, error = %d\n", error); return (-1); } sc->sc_ccbs_paddr = sc->sc_dmamap->dm_segs[0].ds_addr; memset(sc->sc_ccbs, 0, size); ccb = (struct cac_ccb *)sc->sc_ccbs; for (i = 0; i < CAC_MAX_CCBS; i++, ccb++) { /* Create the DMA map for this CCB's data */ error = bus_dmamap_create(sc->sc_dmat, CAC_MAX_XFER, CAC_SG_SIZE, CAC_MAX_XFER, 0, BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &ccb->ccb_dmamap_xfer); if (error) { aprint_error_dev(sc->sc_dev, "can't create ccb dmamap (%d)\n", error); break; } ccb->ccb_flags = 0; ccb->ccb_paddr = sc->sc_ccbs_paddr + i * sizeof(struct cac_ccb); SIMPLEQ_INSERT_TAIL(&sc->sc_ccb_free, ccb, ccb_chain); } /* Start firmware background tasks, if needed. */ if (startfw) { if (cac_cmd(sc, CAC_CMD_START_FIRMWARE, &cinfo, sizeof(cinfo), 0, 0, CAC_CCB_DATA_IN, NULL)) { aprint_error_dev(sc->sc_dev, "CAC_CMD_START_FIRMWARE failed\n"); return (-1); } } if (cac_cmd(sc, CAC_CMD_GET_CTRL_INFO, &cinfo, sizeof(cinfo), 0, 0, CAC_CCB_DATA_IN, NULL)) { aprint_error_dev(sc->sc_dev, "CAC_CMD_GET_CTRL_INFO failed\n"); return (-1); } strlcpy(firm, cinfo.firm_rev, 4+1); printf("%s: %d channels, firmware <%s>\n", device_xname(sc->sc_dev), cinfo.scsi_chips, firm); /* Limit number of units to size of our sc_unitmask */ sc->sc_nunits = cinfo.num_drvs; if (sc->sc_nunits > sizeof(sc->sc_unitmask) * NBBY) sc->sc_nunits = sizeof(sc->sc_unitmask) * NBBY; /* Attach our units */ sc->sc_unitmask = 0; cac_rescan(sc->sc_dev, "cac", 0); /* Set our `shutdownhook' before we start any device activity. */ if (cac_sdh == NULL) cac_sdh = shutdownhook_establish(cac_shutdown, NULL); mutex_enter(&sc->sc_mutex); (*sc->sc_cl.cl_intr_enable)(sc, CAC_INTR_ENABLE); mutex_exit(&sc->sc_mutex); #if NBIO > 0 if (bio_register(sc->sc_dev, cac_ioctl) != 0) aprint_error_dev(sc->sc_dev, "controller registration failed"); else sc->sc_ioctl = cac_ioctl; if (cac_create_sensors(sc) != 0) aprint_error_dev(sc->sc_dev, "unable to create sensors\n"); #endif return (0); }