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); }
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); }
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; } }
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); }
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); }
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); } }