Exemple #1
0
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;
}
Exemple #2
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));
}
Exemple #3
0
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));
}
Exemple #4
0
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);
}
Exemple #5
0
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);
}
Exemple #6
0
/*
 * 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);
	}
}
Exemple #7
0
/*
 * 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);
}
Exemple #8
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);
}