Пример #1
0
void
vdsk_scsi_inquiry(struct scsi_xfer *xs)
{
	struct vdsk_softc *sc = xs->sc_link->adapter_softc;
	struct scsi_inquiry_data inq;
	char buf[5];

	bzero(&inq, sizeof(inq));

	switch (sc->sc_vd_mtype) {
	case VD_MEDIA_TYPE_CD:
	case VD_MEDIA_TYPE_DVD:
		inq.device = T_CDROM;
		break;

	case VD_MEDIA_TYPE_FIXED:
	default:
		inq.device = T_DIRECT;
		break;
	}

	inq.version = 0x05; /* SPC-3 */
	inq.response_format = 2;
	inq.additional_length = 32;
	inq.flags |= SID_CmdQue;
	bcopy("SUN     ", inq.vendor, sizeof(inq.vendor));
	bcopy("Virtual Disk    ", inq.product, sizeof(inq.product));
	snprintf(buf, sizeof(buf), "%u.%u ", sc->sc_major, sc->sc_minor);
	bcopy(buf, inq.revision, sizeof(inq.revision));

	bcopy(&inq, xs->data, MIN(sizeof(inq), xs->datalen));

	vdsk_scsi_done(xs, XS_NOERROR);
}
Пример #2
0
void
vdsk_scsi_inq(struct scsi_xfer *xs)
{
	struct scsi_inquiry *inq = (struct scsi_inquiry *)xs->cmd;

	if (ISSET(inq->flags, SI_EVPD))
		vdsk_scsi_done(xs, XS_DRIVER_STUFFUP);
	else
		vdsk_scsi_inquiry(xs);
}
Пример #3
0
void
vdsk_rx_vio_dring_data(struct vdsk_softc *sc, struct vio_msg_tag *tag)
{
	switch(tag->stype) {
	case VIO_SUBTYPE_INFO:
		DPRINTF(("DATA/INFO/DRING_DATA\n"));
		break;

	case VIO_SUBTYPE_ACK:
	{
		struct scsi_xfer *xs;
		struct ldc_map *map = sc->sc_lm;
		int cons, error;
		int cookie, idx;
		int len;

		cons = sc->sc_tx_cons;
		while (sc->sc_vd->vd_desc[cons].hdr.dstate == VIO_DESC_DONE) {
			xs = sc->sc_vsd[cons].vsd_xs;

			cookie = 0;
			len = xs->datalen;
			while (len > 0) {
				idx = sc->sc_vsd[cons].vsd_map_idx[cookie++];
				map->lm_slot[idx].entry = 0;
				map->lm_count--;
				len -= PAGE_SIZE;
			}

			error = XS_NOERROR;
			if (sc->sc_vd->vd_desc[cons].status != 0)
				error = XS_DRIVER_STUFFUP;
			xs->resid = xs->datalen -
			    sc->sc_vd->vd_desc[cons].size;
			vdsk_scsi_done(xs, error);

			sc->sc_vd->vd_desc[cons++].hdr.dstate = VIO_DESC_FREE;
			cons &= (sc->sc_vd->vd_nentries - 1);
			sc->sc_tx_cnt--;
		}
		sc->sc_tx_cons = cons;
		break;
	}

	case VIO_SUBTYPE_NACK:
		DPRINTF(("DATA/NACK/DRING_DATA\n"));
		break;

	default:
		DPRINTF(("DATA/0x%02x/DRING_DATA\n", tag->stype));
		break;
	}
}
Пример #4
0
void
vdsk_scsi_capacity16(struct scsi_xfer *xs)
{
	struct vdsk_softc *sc = xs->sc_link->adapter_softc;
	struct scsi_read_cap_data_16 rcd;

	bzero(&rcd, sizeof(rcd));

	_lto8b(sc->sc_vdisk_size - 1, rcd.addr);
	_lto4b(sc->sc_vdisk_block_size, rcd.length);

	bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen));

	vdsk_scsi_done(xs, XS_NOERROR);
}
Пример #5
0
void
vdsk_scsi_capacity(struct scsi_xfer *xs)
{
	struct vdsk_softc *sc = xs->sc_link->adapter_softc;
	struct scsi_read_cap_data rcd;
	uint64_t capacity;

	bzero(&rcd, sizeof(rcd));

	capacity = sc->sc_vdisk_size - 1;
	if (capacity > 0xffffffff)
		capacity = 0xffffffff;

	_lto4b(capacity, rcd.addr);
	_lto4b(sc->sc_vdisk_block_size, rcd.length);

	bcopy(&rcd, xs->data, MIN(sizeof(rcd), xs->datalen));

	vdsk_scsi_done(xs, XS_NOERROR);
}
Пример #6
0
void
vdsk_scsi_cmd(struct scsi_xfer *xs)
{
	struct scsi_rw *rw;
	struct scsi_rw_big *rwb;
	struct scsi_rw_12 *rw12;
	struct scsi_rw_16 *rw16;
	u_int64_t lba;
	u_int32_t sector_count;
	uint8_t operation;

	switch (xs->cmd->opcode) {
	case READ_BIG:
	case READ_COMMAND:
	case READ_12:
	case READ_16:
		operation = VD_OP_BREAD;
		break;
	case WRITE_BIG:
	case WRITE_COMMAND:
	case WRITE_12:
	case WRITE_16:
		operation = VD_OP_BWRITE;
		break;

	case SYNCHRONIZE_CACHE:
		operation = VD_OP_FLUSH;
		break;

	case INQUIRY:
		vdsk_scsi_inq(xs);
		return;
	case READ_CAPACITY:
		vdsk_scsi_capacity(xs);
		return;
	case READ_CAPACITY_16:
		vdsk_scsi_capacity16(xs);
		return;

	case TEST_UNIT_READY:
	case START_STOP:
	case PREVENT_ALLOW:
		vdsk_scsi_done(xs, XS_NOERROR);
		return;

	default:
		printf("%s cmd 0x%02x\n", __func__, xs->cmd->opcode);
	case MODE_SENSE:
	case MODE_SENSE_BIG:
	case REPORT_LUNS:
	case READ_TOC:
		vdsk_scsi_done(xs, XS_DRIVER_STUFFUP);
		return;
	}

	/*
	 * READ/WRITE/SYNCHRONIZE commands. SYNCHRONIZE CACHE has same
	 * layout as 10-byte READ/WRITE commands.
	 */
	if (xs->cmdlen == 6) {
		rw = (struct scsi_rw *)xs->cmd;
		lba = _3btol(rw->addr) & (SRW_TOPADDR << 16 | 0xffff);
		sector_count = rw->length ? rw->length : 0x100;
	} else if (xs->cmdlen == 10) {
		rwb = (struct scsi_rw_big *)xs->cmd;
		lba = _4btol(rwb->addr);
		sector_count = _2btol(rwb->length);
	} else if (xs->cmdlen == 12) {
		rw12 = (struct scsi_rw_12 *)xs->cmd;
		lba = _4btol(rw12->addr);
		sector_count = _4btol(rw12->length);
	} else if (xs->cmdlen == 16) {
		rw16 = (struct scsi_rw_16 *)xs->cmd;
		lba = _8btol(rw16->addr);
		sector_count = _4btol(rw16->length);
	}

{
	struct vdsk_softc *sc = xs->sc_link->adapter_softc;
	struct ldc_map *map = sc->sc_lm;
	struct vio_dring_msg dm;
	vaddr_t va;
	paddr_t pa;
	psize_t nbytes;
	int len, ncookies;
	int desc, s;
	int timeout;

	s = splbio();
	desc = sc->sc_tx_prod;

	ncookies = 0;
	len = xs->datalen;
	va = (vaddr_t)xs->data;
	while (len > 0) {
		KASSERT(ncookies < MAXPHYS / PAGE_SIZE);
		pmap_extract(pmap_kernel(), va, &pa);
		while (map->lm_slot[map->lm_next].entry != 0) {
			map->lm_next++;
			map->lm_next &= (map->lm_nentries - 1);
		}
		map->lm_slot[map->lm_next].entry = (pa & LDC_MTE_RA_MASK);
		map->lm_slot[map->lm_next].entry |= LDC_MTE_CPR | LDC_MTE_CPW;
		map->lm_slot[map->lm_next].entry |= LDC_MTE_IOR | LDC_MTE_IOW;
		map->lm_slot[map->lm_next].entry |= LDC_MTE_R | LDC_MTE_W;
		map->lm_count++;

		nbytes = MIN(len, PAGE_SIZE - (pa & PAGE_MASK));

		sc->sc_vd->vd_desc[desc].cookie[ncookies].addr =
		    map->lm_next << PAGE_SHIFT | (pa & PAGE_MASK);
		sc->sc_vd->vd_desc[desc].cookie[ncookies].size = nbytes;

		sc->sc_vsd[desc].vsd_map_idx[ncookies] = map->lm_next;
		va += nbytes;
		len -= nbytes;
		ncookies++;
	}

	sc->sc_vd->vd_desc[desc].hdr.ack = 1;
	sc->sc_vd->vd_desc[desc].operation = operation;
	sc->sc_vd->vd_desc[desc].slice = VD_SLICE_NONE;
	sc->sc_vd->vd_desc[desc].status = 0xffffffff;
	sc->sc_vd->vd_desc[desc].offset = lba;
	sc->sc_vd->vd_desc[desc].size = xs->datalen;
	sc->sc_vd->vd_desc[desc].ncookies = ncookies;
	membar(Sync);
	sc->sc_vd->vd_desc[desc].hdr.dstate = VIO_DESC_READY;

	sc->sc_vsd[desc].vsd_xs = xs;
	sc->sc_vsd[desc].vsd_ncookies = ncookies;

	sc->sc_tx_prod++;
	sc->sc_tx_prod &= (sc->sc_vd->vd_nentries - 1);

	bzero(&dm, sizeof(dm));
	dm.tag.type = VIO_TYPE_DATA;
	dm.tag.stype = VIO_SUBTYPE_INFO;
	dm.tag.stype_env = VIO_DRING_DATA;
	dm.tag.sid = sc->sc_local_sid;
	dm.seq_no = sc->sc_seq_no++;
	dm.dring_ident = sc->sc_dring_ident;
	dm.start_idx = dm.end_idx = desc;
	vdsk_sendmsg(sc, &dm, sizeof(dm));

	if (!ISSET(xs->flags, SCSI_POLL)) {
		splx(s);
		return;
	}

	timeout = 1000;
	do {
		if (vdsk_rx_intr(sc) &&
		    sc->sc_vd->vd_desc[desc].status == VIO_DESC_FREE)
			break;

		delay(1000);
	} while(--timeout > 0);
	splx(s);
}
}