Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
Show First 20 Lines • Show All 736 Lines • ▼ Show 20 Lines | hv_storvsc_on_iocompletion(struct storvsc_softc *sc, | ||||
vm_srb = &vstor_packet->u.vm_srb; | vm_srb = &vstor_packet->u.vm_srb; | ||||
/* | /* | ||||
* Copy some fields of the host's response into the request structure, | * Copy some fields of the host's response into the request structure, | ||||
* because the fields will be used later in storvsc_io_done(). | * because the fields will be used later in storvsc_io_done(). | ||||
*/ | */ | ||||
request->vstor_packet.u.vm_srb.scsi_status = vm_srb->scsi_status; | request->vstor_packet.u.vm_srb.scsi_status = vm_srb->scsi_status; | ||||
request->vstor_packet.u.vm_srb.srb_status = vm_srb->srb_status; | |||||
request->vstor_packet.u.vm_srb.transfer_len = vm_srb->transfer_len; | request->vstor_packet.u.vm_srb.transfer_len = vm_srb->transfer_len; | ||||
if (((vm_srb->scsi_status & 0xFF) == SCSI_STATUS_CHECK_COND) && | if (((vm_srb->scsi_status & 0xFF) == SCSI_STATUS_CHECK_COND) && | ||||
(vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)) { | (vm_srb->srb_status & SRB_STATUS_AUTOSENSE_VALID)) { | ||||
/* Autosense data available */ | /* Autosense data available */ | ||||
KASSERT(vm_srb->sense_info_len <= request->sense_info_len, | KASSERT(vm_srb->sense_info_len <= request->sense_info_len, | ||||
("vm_srb->sense_info_len <= " | ("vm_srb->sense_info_len <= " | ||||
▲ Show 20 Lines • Show All 1,249 Lines • ▼ Show 20 Lines | create_storvsc_request(union ccb *ccb, struct hv_storvsc_request *reqp) | ||||
default: | default: | ||||
printf("Unknow flags: %d\n", ccb->ccb_h.flags); | printf("Unknow flags: %d\n", ccb->ccb_h.flags); | ||||
return(EINVAL); | return(EINVAL); | ||||
} | } | ||||
return(0); | return(0); | ||||
} | } | ||||
/* | |||||
* SCSI Inquiry checks qualifier and type. | |||||
* If qualifier is 011b, means the device server is not capable | |||||
* of supporting a peripheral device on this logical unit, and | |||||
* the type should be set to 1Fh. | |||||
* | |||||
* Return 1 if it is valid, 0 otherwise. | |||||
*/ | |||||
static inline int | |||||
is_inquiry_valid(const struct scsi_inquiry_data *inq_data) | |||||
{ | |||||
uint8_t type; | |||||
if (SID_QUAL(inq_data) != SID_QUAL_LU_CONNECTED) { | |||||
return (0); | |||||
} | |||||
type = SID_TYPE(inq_data); | |||||
if (type == T_NODEVICE) { | |||||
return (0); | |||||
} | |||||
return (1); | |||||
} | |||||
/** | /** | ||||
* @brief completion function before returning to CAM | * @brief completion function before returning to CAM | ||||
* | * | ||||
* I/O process has been completed and the result needs | * I/O process has been completed and the result needs | ||||
* to be passed to the CAM layer. | * to be passed to the CAM layer. | ||||
* Free resources related to this request. | * Free resources related to this request. | ||||
* | * | ||||
* @param reqp pointer to a request structure | * @param reqp pointer to a request structure | ||||
*/ | */ | ||||
static void | static void | ||||
storvsc_io_done(struct hv_storvsc_request *reqp) | storvsc_io_done(struct hv_storvsc_request *reqp) | ||||
{ | { | ||||
union ccb *ccb = reqp->ccb; | union ccb *ccb = reqp->ccb; | ||||
struct ccb_scsiio *csio = &ccb->csio; | struct ccb_scsiio *csio = &ccb->csio; | ||||
struct storvsc_softc *sc = reqp->softc; | struct storvsc_softc *sc = reqp->softc; | ||||
struct vmscsi_req *vm_srb = &reqp->vstor_packet.u.vm_srb; | struct vmscsi_req *vm_srb = &reqp->vstor_packet.u.vm_srb; | ||||
bus_dma_segment_t *ori_sglist = NULL; | bus_dma_segment_t *ori_sglist = NULL; | ||||
int ori_sg_count = 0; | int ori_sg_count = 0; | ||||
/* destroy bounce buffer if it is used */ | /* destroy bounce buffer if it is used */ | ||||
if (reqp->bounce_sgl_count) { | if (reqp->bounce_sgl_count) { | ||||
ori_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr; | ori_sglist = (bus_dma_segment_t *)ccb->csio.data_ptr; | ||||
ori_sg_count = ccb->csio.sglist_cnt; | ori_sg_count = ccb->csio.sglist_cnt; | ||||
/* | /* | ||||
* If it is READ operation, we should copy back the data | * If it is READ operation, we should copy back the data | ||||
* to original SG list. | * to original SG list. | ||||
Show All 37 Lines | #ifdef notyet | ||||
if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { | if (ccb->ccb_h.timeout != CAM_TIME_INFINITY) { | ||||
callout_drain(&reqp->callout); | callout_drain(&reqp->callout); | ||||
} | } | ||||
#endif | #endif | ||||
ccb->ccb_h.status &= ~CAM_SIM_QUEUED; | ccb->ccb_h.status &= ~CAM_SIM_QUEUED; | ||||
ccb->ccb_h.status &= ~CAM_STATUS_MASK; | ccb->ccb_h.status &= ~CAM_STATUS_MASK; | ||||
if (vm_srb->scsi_status == SCSI_STATUS_OK) { | if (vm_srb->scsi_status == SCSI_STATUS_OK) { | ||||
const struct scsi_generic *cmd; | if (vm_srb->srb_status != SRB_STATUS_SUCCESS) { | ||||
/* | char error[64]; | ||||
* Check whether the data for INQUIRY cmd is valid or | ccb->ccb_h.status |= CAM_SEL_TIMEOUT; | ||||
* not. Windows 10 and Windows 2016 send all zero | /** | ||||
* inquiry data to VM even for unpopulated slots. | * Handle error: | ||||
* If there are errors, for example, invalid LUN, | |||||
* host will inform VM through SRB flags. | |||||
*/ | */ | ||||
if (vm_srb->srb_status == SRB_STATUS_INVALID_LUN) { | |||||
snprintf(error, sizeof(error), | |||||
"invalid LUN %d\n", vm_srb->lun); | |||||
} else { | |||||
snprintf(error, sizeof(error), | |||||
"Unknown SRB flag: %d\n", vm_srb->srb_status); | |||||
} | |||||
mtx_lock(&sc->hs_lock); | |||||
xpt_print(ccb->ccb_h.path, "%s", error); | |||||
mtx_unlock(&sc->hs_lock); | |||||
} else { | |||||
ccb->ccb_h.status |= CAM_REQ_CMP; | |||||
} | |||||
const struct scsi_generic *cmd; | |||||
cmd = (const struct scsi_generic *) | cmd = (const struct scsi_generic *) | ||||
((ccb->ccb_h.flags & CAM_CDB_POINTER) ? | ((ccb->ccb_h.flags & CAM_CDB_POINTER) ? | ||||
csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes); | csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes); | ||||
if (cmd->opcode == INQUIRY) { | if (cmd->opcode == INQUIRY) { | ||||
/* | |||||
* The host of Windows 10 or 2016 server will response | |||||
* the inquiry request with invalid data for unexisted device: | |||||
[0x7f 0x0 0x5 0x2 0x1f ... ] | |||||
* But on windows 2012 R2, the response is: | |||||
[0x7f 0x0 0x0 0x0 0x0 ] | |||||
* That is why here wants to validate the inquiry response. | |||||
* The validation will skip the INQUIRY whose response is short, | |||||
* which is less than SHORT_INQUIRY_LENGTH (36). | |||||
* | |||||
* For more information about INQUIRY, please refer to: | |||||
* ftp://ftp.avc-pioneer.com/Mtfuji_7/Proposal/Jun09/INQUIRY.pdf | |||||
*/ | |||||
struct scsi_inquiry_data *inq_data = | struct scsi_inquiry_data *inq_data = | ||||
(struct scsi_inquiry_data *)csio->data_ptr; | (struct scsi_inquiry_data *)csio->data_ptr; | ||||
uint8_t* resp_buf = (uint8_t*)csio->data_ptr; | uint8_t* resp_buf = (uint8_t*)csio->data_ptr; | ||||
/* Get the buffer length reported by host */ | /* Get the buffer length reported by host */ | ||||
int resp_xfer_len = vm_srb->transfer_len; | int resp_xfer_len = vm_srb->transfer_len; | ||||
/* Get the available buffer length */ | /* Get the available buffer length */ | ||||
int resp_buf_len = resp_xfer_len >= 5 ? resp_buf[4] + 5 : 0; | int resp_buf_len = resp_xfer_len >= 5 ? | ||||
int data_len = (resp_buf_len < resp_xfer_len) ? resp_buf_len : resp_xfer_len; | resp_buf[4] + 5 : 0; | ||||
if (data_len < SHORT_INQUIRY_LENGTH) { | int data_len = (resp_buf_len < resp_xfer_len) ? | ||||
ccb->ccb_h.status |= CAM_REQ_CMP; | resp_buf_len : resp_xfer_len; | ||||
if (bootverbose && data_len >= 5) { | if (bootverbose && data_len >= 5) { | ||||
mtx_lock(&sc->hs_lock); | mtx_lock(&sc->hs_lock); | ||||
xpt_print(ccb->ccb_h.path, | xpt_print(ccb->ccb_h.path, | ||||
"storvsc skips the validation for short inquiry (%d)" | "storvsc inquiry (%d)" | ||||
" [%x %x %x %x %x]\n", | " [%x %x %x %x %x ... ]\n", | ||||
data_len,resp_buf[0],resp_buf[1],resp_buf[2], | data_len, resp_buf[0], resp_buf[1], resp_buf[2], | ||||
resp_buf[3],resp_buf[4]); | resp_buf[3], resp_buf[4]); | ||||
mtx_unlock(&sc->hs_lock); | mtx_unlock(&sc->hs_lock); | ||||
} | } | ||||
} else if (is_inquiry_valid(inq_data) == 0) { | if (vm_srb->srb_status == SRB_STATUS_SUCCESS && | ||||
ccb->ccb_h.status |= CAM_DEV_NOT_THERE; | data_len > SHORT_INQUIRY_LENGTH) { | ||||
if (bootverbose && data_len >= 5) { | |||||
mtx_lock(&sc->hs_lock); | |||||
xpt_print(ccb->ccb_h.path, | |||||
"storvsc uninstalled invalid device" | |||||
" [%x %x %x %x %x]\n", | |||||
resp_buf[0],resp_buf[1],resp_buf[2],resp_buf[3],resp_buf[4]); | |||||
mtx_unlock(&sc->hs_lock); | |||||
} | |||||
} else { | |||||
char vendor[16]; | char vendor[16]; | ||||
cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), | cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), | ||||
sizeof(vendor)); | sizeof(vendor)); | ||||
/** | /** | ||||
* XXX: upgrade SPC2 to SPC3 if host is WIN8 or WIN2012 R2 | * XXX: upgrade SPC2 to SPC3 if host is WIN8 or WIN2012 R2 | ||||
* in order to support UNMAP feature | * in order to support UNMAP feature | ||||
*/ | */ | ||||
if (!strncmp(vendor,"Msft",4) && | if (!strncmp(vendor, "Msft", 4) && | ||||
SID_ANSI_REV(inq_data) == SCSI_REV_SPC2 && | SID_ANSI_REV(inq_data) == SCSI_REV_SPC2 && | ||||
(vmstor_proto_version == VMSTOR_PROTOCOL_VERSION_WIN8_1 || | (vmstor_proto_version == VMSTOR_PROTOCOL_VERSION_WIN8_1 || | ||||
vmstor_proto_version== VMSTOR_PROTOCOL_VERSION_WIN8)) { | vmstor_proto_version == VMSTOR_PROTOCOL_VERSION_WIN8)) { | ||||
inq_data->version = SCSI_REV_SPC3; | inq_data->version = SCSI_REV_SPC3; | ||||
if (bootverbose) { | if (bootverbose) { | ||||
mtx_lock(&sc->hs_lock); | mtx_lock(&sc->hs_lock); | ||||
xpt_print(ccb->ccb_h.path, | xpt_print(ccb->ccb_h.path, | ||||
"storvsc upgrades SPC2 to SPC3\n"); | "storvsc upgrades SPC2 to SPC3\n"); | ||||
mtx_unlock(&sc->hs_lock); | mtx_unlock(&sc->hs_lock); | ||||
} | } | ||||
} | } | ||||
ccb->ccb_h.status |= CAM_REQ_CMP; | |||||
if (bootverbose) { | |||||
mtx_lock(&sc->hs_lock); | |||||
xpt_print(ccb->ccb_h.path, | |||||
"storvsc has passed inquiry response (%d) validation\n", | |||||
data_len); | |||||
mtx_unlock(&sc->hs_lock); | |||||
} | } | ||||
} | |||||
} else { | |||||
ccb->ccb_h.status |= CAM_REQ_CMP; | |||||
} | } | ||||
} else { | } else { | ||||
mtx_lock(&sc->hs_lock); | mtx_lock(&sc->hs_lock); | ||||
xpt_print(ccb->ccb_h.path, | xpt_print(ccb->ccb_h.path, | ||||
"storvsc scsi_status = %d\n", | "storvsc scsi_status = %d\n", | ||||
vm_srb->scsi_status); | vm_srb->scsi_status); | ||||
mtx_unlock(&sc->hs_lock); | mtx_unlock(&sc->hs_lock); | ||||
ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; | ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; | ||||
▲ Show 20 Lines • Show All 59 Lines • Show Last 20 Lines |