Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/hyperv/storvsc/hv_storvsc_drv_freebsd.c
Show First 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | |||||
static u_int hv_storvsc_max_io = 512; | static u_int hv_storvsc_max_io = 512; | ||||
SYSCTL_UINT(_hw_storvsc, OID_AUTO, max_io, CTLFLAG_RDTUN, | SYSCTL_UINT(_hw_storvsc, OID_AUTO, max_io, CTLFLAG_RDTUN, | ||||
&hv_storvsc_max_io, 0, "Hyper-V storage max io limit"); | &hv_storvsc_max_io, 0, "Hyper-V storage max io limit"); | ||||
static int hv_storvsc_chan_cnt = 0; | static int hv_storvsc_chan_cnt = 0; | ||||
SYSCTL_INT(_hw_storvsc, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, | SYSCTL_INT(_hw_storvsc, OID_AUTO, chan_cnt, CTLFLAG_RDTUN, | ||||
&hv_storvsc_chan_cnt, 0, "# of channels to use"); | &hv_storvsc_chan_cnt, 0, "# of channels to use"); | ||||
#ifdef DIAGNOSTIC | |||||
static int hv_storvsc_srb_status = -1; | |||||
SYSCTL_INT(_hw_storvsc, OID_AUTO, srb_status, CTLFLAG_RW, | |||||
&hv_storvsc_srb_status, 0, "srb_status to inject"); | |||||
TUNABLE_INT("hw_storvsc.srb_status", &hv_storvsc_srb_status); | |||||
#endif /* DIAGNOSTIC */ | |||||
#define STORVSC_MAX_IO \ | #define STORVSC_MAX_IO \ | ||||
vmbus_chan_prplist_nelem(hv_storvsc_ringbuffer_size, \ | vmbus_chan_prplist_nelem(hv_storvsc_ringbuffer_size, \ | ||||
STORVSC_DATA_SEGCNT_MAX, VSTOR_PKT_SIZE) | STORVSC_DATA_SEGCNT_MAX, VSTOR_PKT_SIZE) | ||||
struct hv_storvsc_sysctl { | struct hv_storvsc_sysctl { | ||||
u_long data_bio_cnt; | u_long data_bio_cnt; | ||||
u_long data_vaddr_cnt; | u_long data_vaddr_cnt; | ||||
▲ Show 20 Lines • Show All 537 Lines • ▼ Show 20 Lines | hv_storvsc_io_request(struct storvsc_softc *sc, | ||||
vstor_packet->u.vm_srb.sense_info_len = sense_buffer_size; | vstor_packet->u.vm_srb.sense_info_len = sense_buffer_size; | ||||
vstor_packet->u.vm_srb.transfer_len = | vstor_packet->u.vm_srb.transfer_len = | ||||
request->prp_list.gpa_range.gpa_len; | request->prp_list.gpa_range.gpa_len; | ||||
vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB; | vstor_packet->operation = VSTOR_OPERATION_EXECUTESRB; | ||||
ch_sel = (vstor_packet->u.vm_srb.lun + curcpu) % sc->hs_nchan; | ch_sel = (vstor_packet->u.vm_srb.lun + curcpu) % sc->hs_nchan; | ||||
/* | |||||
* If we are panic'ing, then we are dumping core. Since storvsc_polls | |||||
* always uses sc->hs_chan, then we must send to that channel or a poll | |||||
* timeout will occur. | |||||
*/ | |||||
if (panicstr) { | |||||
outgoing_channel = sc->hs_chan; | |||||
} else { | |||||
outgoing_channel = sc->hs_sel_chan[ch_sel]; | outgoing_channel = sc->hs_sel_chan[ch_sel]; | ||||
} | |||||
mtx_unlock(&request->softc->hs_lock); | mtx_unlock(&request->softc->hs_lock); | ||||
if (request->prp_list.gpa_range.gpa_len) { | if (request->prp_list.gpa_range.gpa_len) { | ||||
ret = vmbus_chan_send_prplist(outgoing_channel, | ret = vmbus_chan_send_prplist(outgoing_channel, | ||||
&request->prp_list.gpa_range, request->prp_cnt, | &request->prp_list.gpa_range, request->prp_cnt, | ||||
vstor_packet, VSTOR_PKT_SIZE, (uint64_t)(uintptr_t)request); | vstor_packet, VSTOR_PKT_SIZE, (uint64_t)(uintptr_t)request); | ||||
} else { | } else { | ||||
ret = vmbus_chan_send(outgoing_channel, | ret = vmbus_chan_send(outgoing_channel, | ||||
▲ Show 20 Lines • Show All 1,434 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
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); | ||||
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; | ||||
int srb_status = SRB_STATUS(vm_srb->srb_status); | int srb_status = SRB_STATUS(vm_srb->srb_status); | ||||
#ifdef DIAGNOSTIC | |||||
if (hv_storvsc_srb_status != -1) { | |||||
srb_status = SRB_STATUS(hv_storvsc_srb_status & 0x3f); | |||||
hv_storvsc_srb_status = -1; | |||||
} | |||||
#endif /* DIAGNOSTIC */ | |||||
if (vm_srb->scsi_status == SCSI_STATUS_OK) { | if (vm_srb->scsi_status == SCSI_STATUS_OK) { | ||||
if (srb_status != SRB_STATUS_SUCCESS) { | if (srb_status != SRB_STATUS_SUCCESS) { | ||||
bool log_error = true; | |||||
switch (srb_status) { | |||||
case SRB_STATUS_PENDING: | |||||
/* We should never get this */ | |||||
panic("storvsc_io_done: SRB_STATUS_PENDING"); | |||||
break; | |||||
case SRB_STATUS_ABORTED: | |||||
/* | /* | ||||
* If there are errors, for example, invalid LUN, | * storvsc doesn't support aborts yet | ||||
* host will inform VM through SRB status. | * but if we ever get this status | ||||
* the I/O is complete - treat it as a | |||||
* timeout | |||||
*/ | */ | ||||
if (bootverbose) { | ccb->ccb_h.status |= CAM_CMD_TIMEOUT; | ||||
if (srb_status == SRB_STATUS_INVALID_LUN) { | break; | ||||
xpt_print(ccb->ccb_h.path, | case SRB_STATUS_ABORT_FAILED: | ||||
"invalid LUN %d for op: %s\n", | /* We should never get this */ | ||||
vm_srb->lun, | panic("storvsc_io_done: SRB_STATUS_ABORT_FAILED"); | ||||
break; | |||||
case SRB_STATUS_ERROR: | |||||
/* | |||||
* We should never get this. | |||||
* Treat it as a CAM_UNREC_HBA_ERROR. | |||||
* It will be retried | |||||
*/ | |||||
ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; | |||||
break; | |||||
case SRB_STATUS_BUSY: | |||||
/* Host is busy. Delay and retry */ | |||||
ccb->ccb_h.status |= CAM_BUSY; | |||||
break; | |||||
case SRB_STATUS_INVALID_REQUEST: | |||||
case SRB_STATUS_INVALID_PATH_ID: | |||||
case SRB_STATUS_NO_DEVICE: | |||||
case SRB_STATUS_INVALID_TARGET_ID: | |||||
/* | |||||
* These indicate an invalid address | |||||
* and really should never be seen. | |||||
* A CAM_PATH_INVALID could be | |||||
* used here but I want to run | |||||
* down retries. Do a CAM_BUSY | |||||
* since the host might be having issues. | |||||
*/ | |||||
ccb->ccb_h.status |= CAM_BUSY; | |||||
break; | |||||
case SRB_STATUS_TIMEOUT: | |||||
case SRB_STATUS_COMMAND_TIMEOUT: | |||||
/* The backend has timed this out */ | |||||
ccb->ccb_h.status |= CAM_BUSY; | |||||
break; | |||||
/* Some old pSCSI errors below */ | |||||
case SRB_STATUS_SELECTION_TIMEOUT: | |||||
case SRB_STATUS_MESSAGE_REJECTED: | |||||
case SRB_STATUS_PARITY_ERROR: | |||||
case SRB_STATUS_NO_HBA: | |||||
case SRB_STATUS_DATA_OVERRUN: | |||||
case SRB_STATUS_UNEXPECTED_BUS_FREE: | |||||
case SRB_STATUS_PHASE_SEQUENCE_FAILURE: | |||||
/* | |||||
* Old pSCSI responses, should never get. | |||||
* If we do treat as a CAM_UNREC_HBA_ERROR | |||||
* which will be retried | |||||
*/ | |||||
ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; | |||||
break; | |||||
case SRB_STATUS_BUS_RESET: | |||||
ccb->ccb_h.status |= CAM_SCSI_BUS_RESET; | |||||
break; | |||||
case SRB_STATUS_BAD_SRB_BLOCK_LENGTH: | |||||
/* | |||||
* The request block is malformed and | |||||
* I doubt it is from the guest. Just retry. | |||||
*/ | |||||
ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; | |||||
break; | |||||
/* Not used statuses just retry */ | |||||
case SRB_STATUS_REQUEST_FLUSHED: | |||||
case SRB_STATUS_BAD_FUNCTION: | |||||
case SRB_STATUS_NOT_POWERED: | |||||
ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; | |||||
break; | |||||
case SRB_STATUS_INVALID_LUN: | |||||
/* | |||||
* Don't log an EMS for this response since | |||||
* there is no device at this LUN. This is a | |||||
* normal and expected response when a device | |||||
* is detached. | |||||
*/ | |||||
ccb->ccb_h.status |= CAM_DEV_NOT_THERE; | |||||
log_error = false; | |||||
break; | |||||
case SRB_STATUS_ERROR_RECOVERY: | |||||
case SRB_STATUS_LINK_DOWN: | |||||
/* | |||||
* I don't ever expect these from | |||||
* the host but if we ever get | |||||
* retry after a delay | |||||
*/ | |||||
ccb->ccb_h.status |= CAM_BUSY; | |||||
break; | |||||
default: | |||||
/* | |||||
* An undefined response assert on | |||||
* on debug builds else retry | |||||
*/ | |||||
ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; | |||||
KASSERT(srb_status <= SRB_STATUS_LINK_DOWN, | |||||
("storvsc: %s, unexpected srb_status of 0x%x", | |||||
__func__, srb_status)); | |||||
break; | |||||
} | |||||
if (log_error) { | |||||
allanjude: This error message doesn't really read like an error message, maybe:
"The hypervisor's I/O… | |||||
Done Inline ActionsYeah, that's a good idea. Below's what we are thinking. Comments on this before I update the diff? The hypervisor's I/O adapter driver received an unexpected response code 0x%x for operation: %s. If this continues to occur, report the condition to your hypervisor vendor so they can rectify the issue. siderop1_netapp.com: Yeah, that's a good idea. Below's what we are thinking. Comments on this before I update the… | |||||
Not Done Inline ActionsYes, this is exactly what I had in mind. allanjude: Yes, this is exactly what I had in mind. | |||||
xpt_print(ccb->ccb_h.path, "The hypervisor's I/O adapter " | |||||
"driver received an unexpected response code 0x%x " | |||||
"for operation: %s. If this continues to occur, " | |||||
"report the condition to your hypervisor vendor so " | |||||
"they can rectify the issue.\n", srb_status, | |||||
scsi_op_desc(cmd->opcode, NULL)); | scsi_op_desc(cmd->opcode, NULL)); | ||||
} else { | |||||
xpt_print(ccb->ccb_h.path, | |||||
"Unknown SRB flag: %d for op: %s\n", | |||||
srb_status, | |||||
scsi_op_desc(cmd->opcode, NULL)); | |||||
} | } | ||||
} | |||||
ccb->ccb_h.status |= CAM_DEV_NOT_THERE; | |||||
} else { | } else { | ||||
ccb->ccb_h.status |= CAM_REQ_CMP; | ccb->ccb_h.status |= CAM_REQ_CMP; | ||||
} | } | ||||
if (cmd->opcode == INQUIRY && | if (cmd->opcode == INQUIRY && | ||||
srb_status == SRB_STATUS_SUCCESS) { | srb_status == SRB_STATUS_SUCCESS) { | ||||
int resp_xfer_len, resp_buf_len, data_len; | int resp_xfer_len, resp_buf_len, data_len; | ||||
uint8_t *resp_buf = (uint8_t *)csio->data_ptr; | uint8_t *resp_buf = (uint8_t *)csio->data_ptr; | ||||
▲ Show 20 Lines • Show All 207 Lines • Show Last 20 Lines |
This error message doesn't really read like an error message, maybe:
"The hypervisor's I/O adapter driver received an unexpected response code 0x%x for operation: %s"
But is there some way we can expand this message to inform the user what they are expected to do about this? Or what side effects this might cause?