Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/mpr/mpr_sas.c
Show First 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | |||||
#include <cam/cam_xpt_periph.h> | #include <cam/cam_xpt_periph.h> | ||||
#include <cam/cam_periph.h> | #include <cam/cam_periph.h> | ||||
#include <cam/scsi/scsi_all.h> | #include <cam/scsi/scsi_all.h> | ||||
#include <cam/scsi/scsi_message.h> | #include <cam/scsi/scsi_message.h> | ||||
#if __FreeBSD_version >= 900026 | #if __FreeBSD_version >= 900026 | ||||
#include <cam/scsi/smp_all.h> | #include <cam/scsi/smp_all.h> | ||||
#endif | #endif | ||||
#include <dev/nvme/nvme.h> | |||||
#include <dev/mpr/mpi/mpi2_type.h> | #include <dev/mpr/mpi/mpi2_type.h> | ||||
#include <dev/mpr/mpi/mpi2.h> | #include <dev/mpr/mpi/mpi2.h> | ||||
#include <dev/mpr/mpi/mpi2_ioc.h> | #include <dev/mpr/mpi/mpi2_ioc.h> | ||||
#include <dev/mpr/mpi/mpi2_sas.h> | #include <dev/mpr/mpi/mpi2_sas.h> | ||||
#include <dev/mpr/mpi/mpi2_pci.h> | |||||
#include <dev/mpr/mpi/mpi2_cnfg.h> | #include <dev/mpr/mpi/mpi2_cnfg.h> | ||||
#include <dev/mpr/mpi/mpi2_init.h> | #include <dev/mpr/mpi/mpi2_init.h> | ||||
#include <dev/mpr/mpi/mpi2_tool.h> | #include <dev/mpr/mpi/mpi2_tool.h> | ||||
#include <dev/mpr/mpr_ioctl.h> | #include <dev/mpr/mpr_ioctl.h> | ||||
#include <dev/mpr/mprvar.h> | #include <dev/mpr/mprvar.h> | ||||
#include <dev/mpr/mpr_table.h> | #include <dev/mpr/mpr_table.h> | ||||
#include <dev/mpr/mpr_sas.h> | #include <dev/mpr/mpr_sas.h> | ||||
▲ Show 20 Lines • Show All 385 Lines • ▼ Show 20 Lines | mprsas_prepare_volume_remove(struct mprsas_softc *sassc, uint16_t handle) | ||||
mpr_dprint(sc, MPR_INFO, "%s: Sending reset for target ID %d\n", | mpr_dprint(sc, MPR_INFO, "%s: Sending reset for target ID %d\n", | ||||
__func__, targ->tid); | __func__, targ->tid); | ||||
mprsas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD); | mprsas_prepare_for_tm(sc, cm, targ, CAM_LUN_WILDCARD); | ||||
mpr_map_command(sc, cm); | mpr_map_command(sc, cm); | ||||
} | } | ||||
/* | /* | ||||
* The MPT3 firmware performs debounce on the link to avoid transient link | * The firmware performs debounce on the link to avoid transient link errors | ||||
* errors and false removals. When it does decide that link has been lost | * and false removals. When it does decide that link has been lost and a | ||||
* and a device needs to go away, it expects that the host will perform a | * device needs to go away, it expects that the host will perform a target reset | ||||
* target reset and then an op remove. The reset has the side-effect of | * and then an op remove. The reset has the side-effect of aborting any | ||||
* aborting any outstanding requests for the device, which is required for | * outstanding requests for the device, which is required for the op-remove to | ||||
* the op-remove to succeed. It's not clear if the host should check for | * succeed. It's not clear if the host should check for the device coming back | ||||
* the device coming back alive after the reset. | * alive after the reset. | ||||
*/ | */ | ||||
void | void | ||||
mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle) | mprsas_prepare_remove(struct mprsas_softc *sassc, uint16_t handle) | ||||
{ | { | ||||
MPI2_SCSI_TASK_MANAGE_REQUEST *req; | MPI2_SCSI_TASK_MANAGE_REQUEST *req; | ||||
struct mpr_softc *sc; | struct mpr_softc *sc; | ||||
struct mpr_command *cm; | struct mpr_command *cm; | ||||
struct mprsas_target *targ = NULL; | struct mprsas_target *targ = NULL; | ||||
▲ Show 20 Lines • Show All 205 Lines • ▼ Show 20 Lines | mprsas_register_events(struct mpr_softc *sc) | ||||
setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); | setbit(events, MPI2_EVENT_SAS_INIT_TABLE_OVERFLOW); | ||||
setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); | setbit(events, MPI2_EVENT_SAS_TOPOLOGY_CHANGE_LIST); | ||||
setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); | setbit(events, MPI2_EVENT_SAS_ENCL_DEVICE_STATUS_CHANGE); | ||||
setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); | setbit(events, MPI2_EVENT_IR_CONFIGURATION_CHANGE_LIST); | ||||
setbit(events, MPI2_EVENT_IR_VOLUME); | setbit(events, MPI2_EVENT_IR_VOLUME); | ||||
setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK); | setbit(events, MPI2_EVENT_IR_PHYSICAL_DISK); | ||||
setbit(events, MPI2_EVENT_IR_OPERATION_STATUS); | setbit(events, MPI2_EVENT_IR_OPERATION_STATUS); | ||||
setbit(events, MPI2_EVENT_TEMP_THRESHOLD); | setbit(events, MPI2_EVENT_TEMP_THRESHOLD); | ||||
if (sc->facts->MsgVersion >= MPI2_VERSION_02_06) { | |||||
setbit(events, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION); | setbit(events, MPI2_EVENT_ACTIVE_CABLE_EXCEPTION); | ||||
if (sc->mpr_flags & MPR_FLAGS_GEN35_IOC) { | |||||
setbit(events, MPI2_EVENT_PCIE_DEVICE_STATUS_CHANGE); | |||||
setbit(events, MPI2_EVENT_PCIE_ENUMERATION); | |||||
setbit(events, MPI2_EVENT_PCIE_TOPOLOGY_CHANGE_LIST); | |||||
} | |||||
} | |||||
mpr_register_events(sc, events, mprsas_evt_handler, NULL, | mpr_register_events(sc, events, mprsas_evt_handler, NULL, | ||||
&sc->sassc->mprsas_eh); | &sc->sassc->mprsas_eh); | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
▲ Show 20 Lines • Show All 296 Lines • ▼ Show 20 Lines | #endif | ||||
*/ | */ | ||||
sges_per_frame = (sc->chain_frame_size / | sges_per_frame = (sc->chain_frame_size / | ||||
sizeof(MPI2_IEEE_SGE_SIMPLE64)) - 1; | sizeof(MPI2_IEEE_SGE_SIMPLE64)) - 1; | ||||
cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1; | cpi->maxio = (sges_per_frame * sc->facts->MaxChainDepth) + 1; | ||||
cpi->maxio *= PAGE_SIZE; | cpi->maxio *= PAGE_SIZE; | ||||
if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE < | if ((sc->max_io_pages > 0) && (sc->max_io_pages * PAGE_SIZE < | ||||
cpi->maxio)) | cpi->maxio)) | ||||
cpi->maxio = sc->max_io_pages * PAGE_SIZE; | cpi->maxio = sc->max_io_pages * PAGE_SIZE; | ||||
sc->maxio = cpi->maxio; | |||||
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); | mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); | ||||
break; | break; | ||||
} | } | ||||
case XPT_GET_TRAN_SETTINGS: | case XPT_GET_TRAN_SETTINGS: | ||||
{ | { | ||||
struct ccb_trans_settings *cts; | struct ccb_trans_settings *cts; | ||||
struct ccb_trans_settings_sas *sas; | struct ccb_trans_settings_sas *sas; | ||||
struct ccb_trans_settings_scsi *scsi; | struct ccb_trans_settings_scsi *scsi; | ||||
▲ Show 20 Lines • Show All 602 Lines • ▼ Show 20 Lines | if (cm->cm_ccb == NULL) { | ||||
mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n"); | mpr_dprint(sc, MPR_ERROR, "command timeout with NULL ccb\n"); | ||||
return; | return; | ||||
} | } | ||||
targ = cm->cm_targ; | targ = cm->cm_targ; | ||||
targ->timeouts++; | targ->timeouts++; | ||||
mprsas_log_command(cm, MPR_ERROR, "command timeout %d cm %p target " | mprsas_log_command(cm, MPR_ERROR, "command timeout %d cm %p target " | ||||
"%u, handle(0x%04x)\n", cm->cm_ccb->ccb_h.timeout, cm, targ->tid, | "%u, handle(0x%04x)\n", cm->cm_ccb->ccb_h.timeout, cm, targ->tid, | ||||
targ->handle); | targ->handle); | ||||
if (targ->encl_level_valid) { | if (targ->encl_level_valid) { | ||||
mpr_dprint(sc, MPR_ERROR, "At enclosure level %d, slot %d, " | mpr_dprint(sc, MPR_ERROR, "At enclosure level %d, slot %d, " | ||||
"connector name (%4s)\n", targ->encl_level, targ->encl_slot, | "connector name (%4s)\n", targ->encl_level, targ->encl_slot, | ||||
targ->connector_name); | targ->connector_name); | ||||
} | } | ||||
/* XXX first, check the firmware state, to see if it's still | /* XXX first, check the firmware state, to see if it's still | ||||
Show All 27 Lines | else { | ||||
* more credits than disks in an enclosure, and limit | * more credits than disks in an enclosure, and limit | ||||
* ourselves to one TM per target for recovery. | * ourselves to one TM per target for recovery. | ||||
*/ | */ | ||||
mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p failed to " | mpr_dprint(sc, MPR_RECOVERY, "timedout cm %p failed to " | ||||
"allocate a tm\n", cm); | "allocate a tm\n", cm); | ||||
} | } | ||||
} | } | ||||
/** | |||||
* mprsas_build_nvme_unmap - Build Native NVMe DSM command equivalent | |||||
* to SCSI Unmap. | |||||
* Return 0 - for success, | |||||
* 1 - to immediately return back the command with success status to CAM | |||||
* negative value - to fallback to firmware path i.e. issue scsi unmap | |||||
* to FW without any translation. | |||||
*/ | |||||
static int | |||||
mprsas_build_nvme_unmap(struct mpr_softc *sc, struct mpr_command *cm, | |||||
union ccb *ccb, struct mprsas_target *targ) | |||||
{ | |||||
Mpi26NVMeEncapsulatedRequest_t *req = NULL; | |||||
struct ccb_scsiio *csio; | |||||
struct unmap_parm_list *plist; | |||||
struct nvme_dsm_range *nvme_dsm_ranges = NULL; | |||||
struct nvme_command *c; | |||||
int i, res; | |||||
uint16_t ndesc, list_len, data_length; | |||||
struct mpr_prp_page *prp_page_info; | |||||
uint64_t nvme_dsm_ranges_dma_handle; | |||||
csio = &ccb->csio; | |||||
#if __FreeBSD_version >= 1100103 | |||||
list_len = (scsiio_cdb_ptr(csio)[7] << 8 | scsiio_cdb_ptr(csio)[8]); | |||||
#else | |||||
if (csio->ccb_h.flags & CAM_CDB_POINTER) { | |||||
list_len = (ccb->csio.cdb_io.cdb_ptr[7] << 8 | | |||||
ccb->csio.cdb_io.cdb_ptr[8]); | |||||
} else { | |||||
list_len = (ccb->csio.cdb_io.cdb_bytes[7] << 8 | | |||||
ccb->csio.cdb_io.cdb_bytes[8]); | |||||
} | |||||
#endif | |||||
if (!list_len) { | |||||
mpr_dprint(sc, MPR_ERROR, "Parameter list length is Zero\n"); | |||||
return -EINVAL; | |||||
} | |||||
plist = malloc(csio->dxfer_len, M_MPR, M_ZERO|M_NOWAIT); | |||||
if (!plist) { | |||||
mpr_dprint(sc, MPR_ERROR, "Unable to allocate memory to " | |||||
"save UNMAP data\n"); | |||||
return -ENOMEM; | |||||
} | |||||
/* Copy SCSI unmap data to a local buffer */ | |||||
bcopy(csio->data_ptr, plist, csio->dxfer_len); | |||||
/* return back the unmap command to CAM with success status, | |||||
* if number of descripts is zero. | |||||
*/ | |||||
ndesc = be16toh(plist->unmap_blk_desc_data_len) >> 4; | |||||
if (!ndesc) { | |||||
mpr_dprint(sc, MPR_XINFO, "Number of descriptors in " | |||||
"UNMAP cmd is Zero\n"); | |||||
res = 1; | |||||
goto out; | |||||
} | |||||
data_length = ndesc * sizeof(struct nvme_dsm_range); | |||||
if (data_length > targ->MDTS) { | |||||
mpr_dprint(sc, MPR_ERROR, "data length: %d is greater than " | |||||
"Device's MDTS: %d\n", data_length, targ->MDTS); | |||||
res = -EINVAL; | |||||
goto out; | |||||
} | |||||
prp_page_info = mpr_alloc_prp_page(sc); | |||||
KASSERT(prp_page_info != NULL, ("%s: There is no PRP Page for " | |||||
"UNMAP command.\n", __func__)); | |||||
/* | |||||
* Insert the allocated PRP page into the command's PRP page list. This | |||||
* will be freed when the command is freed. | |||||
*/ | |||||
TAILQ_INSERT_TAIL(&cm->cm_prp_page_list, prp_page_info, prp_page_link); | |||||
nvme_dsm_ranges = (struct nvme_dsm_range *)prp_page_info->prp_page; | |||||
nvme_dsm_ranges_dma_handle = prp_page_info->prp_page_busaddr; | |||||
bzero(nvme_dsm_ranges, data_length); | |||||
/* Convert SCSI unmap's descriptor data to NVMe DSM specific Range data | |||||
* for each descriptors contained in SCSI UNMAP data. | |||||
*/ | |||||
for (i = 0; i < ndesc; i++) { | |||||
nvme_dsm_ranges[i].length = | |||||
htole32(be32toh(plist->desc[i].nlb)); | |||||
nvme_dsm_ranges[i].starting_lba = | |||||
htole64(be64toh(plist->desc[i].slba)); | |||||
nvme_dsm_ranges[i].attributes = 0; | |||||
} | |||||
/* Build MPI2.6's NVMe Encapsulated Request Message */ | |||||
req = (Mpi26NVMeEncapsulatedRequest_t *)cm->cm_req; | |||||
bzero(req, sizeof(*req)); | |||||
req->DevHandle = htole16(targ->handle); | |||||
req->Function = MPI2_FUNCTION_NVME_ENCAPSULATED; | |||||
req->Flags = MPI26_NVME_FLAGS_WRITE; | |||||
req->ErrorResponseBaseAddress.High = | |||||
htole32((uint32_t)((uint64_t)cm->cm_sense_busaddr >> 32)); | |||||
req->ErrorResponseBaseAddress.Low = | |||||
htole32(cm->cm_sense_busaddr); | |||||
req->ErrorResponseAllocationLength = | |||||
htole16(sizeof(struct nvme_completion)); | |||||
req->EncapsulatedCommandLength = | |||||
htole16(sizeof(struct nvme_command)); | |||||
req->DataLength = htole32(data_length); | |||||
/* Build NVMe DSM command */ | |||||
c = (struct nvme_command *) req->NVMe_Command; | |||||
c->opc = NVME_OPC_DATASET_MANAGEMENT; | |||||
c->nsid = htole32(csio->ccb_h.target_lun + 1); | |||||
c->cdw10 = htole32(ndesc - 1); | |||||
c->cdw11 = htole32(NVME_DSM_ATTR_DEALLOCATE); | |||||
cm->cm_length = data_length; | |||||
cm->cm_data = NULL; | |||||
cm->cm_complete = mprsas_scsiio_complete; | |||||
cm->cm_complete_data = ccb; | |||||
cm->cm_targ = targ; | |||||
cm->cm_lun = csio->ccb_h.target_lun; | |||||
cm->cm_ccb = ccb; | |||||
cm->cm_desc.Default.RequestFlags = | |||||
MPI26_REQ_DESCRIPT_FLAGS_PCIE_ENCAPSULATED; | |||||
#if __FreeBSD_version >= 1000029 | |||||
callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0, | |||||
mprsas_scsiio_timeout, cm, 0); | |||||
#else //__FreeBSD_version < 1000029 | |||||
callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, | |||||
mprsas_scsiio_timeout, cm); | |||||
#endif //__FreeBSD_version >= 1000029 | |||||
targ->issued++; | |||||
targ->outstanding++; | |||||
TAILQ_INSERT_TAIL(&targ->commands, cm, cm_link); | |||||
ccb->ccb_h.status |= CAM_SIM_QUEUED; | |||||
mprsas_log_command(cm, MPR_XINFO, "%s cm %p ccb %p outstanding %u\n", | |||||
__func__, cm, ccb, targ->outstanding); | |||||
mpr_build_nvme_prp(sc, cm, req, (void *)nvme_dsm_ranges_dma_handle, 0, | |||||
data_length); | |||||
mpr_map_command(sc, cm); | |||||
out: | |||||
free(plist, M_MPR); | |||||
return 0; | |||||
} | |||||
static void | static void | ||||
mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) | mprsas_action_scsiio(struct mprsas_softc *sassc, union ccb *ccb) | ||||
{ | { | ||||
MPI2_SCSI_IO_REQUEST *req; | MPI2_SCSI_IO_REQUEST *req; | ||||
struct ccb_scsiio *csio; | struct ccb_scsiio *csio; | ||||
struct mpr_softc *sc; | struct mpr_softc *sc; | ||||
struct mprsas_target *targ; | struct mprsas_target *targ; | ||||
struct mprsas_lun *lun; | struct mprsas_lun *lun; | ||||
struct mpr_command *cm; | struct mpr_command *cm; | ||||
uint8_t i, lba_byte, *ref_tag_addr; | uint8_t i, lba_byte, *ref_tag_addr, scsi_opcode; | ||||
uint16_t eedp_flags; | uint16_t eedp_flags; | ||||
uint32_t mpi_control; | uint32_t mpi_control; | ||||
int rc; | |||||
sc = sassc->sc; | sc = sassc->sc; | ||||
MPR_FUNCTRACE(sc); | MPR_FUNCTRACE(sc); | ||||
mtx_assert(&sc->mpr_mtx, MA_OWNED); | mtx_assert(&sc->mpr_mtx, MA_OWNED); | ||||
csio = &ccb->csio; | csio = &ccb->csio; | ||||
KASSERT(csio->ccb_h.target_id < sassc->maxtargets, | KASSERT(csio->ccb_h.target_id < sassc->maxtargets, | ||||
("Target %d out of bounds in XPT_SCSI_IO\n", | ("Target %d out of bounds in XPT_SCSI_IO\n", | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { | ||||
sassc->flags |= MPRSAS_QUEUE_FROZEN; | sassc->flags |= MPRSAS_QUEUE_FROZEN; | ||||
} | } | ||||
ccb->ccb_h.status &= ~CAM_SIM_QUEUED; | ccb->ccb_h.status &= ~CAM_SIM_QUEUED; | ||||
ccb->ccb_h.status |= CAM_REQUEUE_REQ; | ccb->ccb_h.status |= CAM_REQUEUE_REQ; | ||||
xpt_done(ccb); | xpt_done(ccb); | ||||
return; | return; | ||||
} | } | ||||
/* For NVME device's issue UNMAP command directly to NVME drives by | |||||
* constructing equivalent native NVMe DataSetManagement command. | |||||
*/ | |||||
#if __FreeBSD_version >= 1100103 | |||||
scsi_opcode = scsiio_cdb_ptr(csio)[0]; | |||||
#else | |||||
if (csio->ccb_h.flags & CAM_CDB_POINTER) | |||||
scsi_opcode = csio->cdb_io.cdb_ptr[0]; | |||||
else | |||||
scsi_opcode = csio->cdb_io.cdb_bytes[0]; | |||||
#endif | |||||
if (scsi_opcode == UNMAP && | |||||
targ->is_nvme && | |||||
(csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) { | |||||
rc = mprsas_build_nvme_unmap(sc, cm, ccb, targ); | |||||
if (rc == 1) { /* return command to CAM with success status */ | |||||
mpr_free_command(sc, cm); | |||||
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); | |||||
xpt_done(ccb); | |||||
return; | |||||
} else if (!rc) /* Issued NVMe Encapsulated Request Message */ | |||||
return; | |||||
} | |||||
req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; | req = (MPI2_SCSI_IO_REQUEST *)cm->cm_req; | ||||
bzero(req, sizeof(*req)); | bzero(req, sizeof(*req)); | ||||
req->DevHandle = htole16(targ->handle); | req->DevHandle = htole16(targ->handle); | ||||
req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; | req->Function = MPI2_FUNCTION_SCSI_IO_REQUEST; | ||||
req->MsgFlags = 0; | req->MsgFlags = 0; | ||||
req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr); | req->SenseBufferLowAddress = htole32(cm->cm_sense_busaddr); | ||||
req->SenseBufferLength = MPR_SENSE_LEN; | req->SenseBufferLength = MPR_SENSE_LEN; | ||||
req->SGLFlags = 0; | req->SGLFlags = 0; | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | if (MPR_SET_LUN(req->LUN, csio->ccb_h.target_lun) != 0) { | ||||
xpt_done(ccb); | xpt_done(ccb); | ||||
return; | return; | ||||
} | } | ||||
if (csio->ccb_h.flags & CAM_CDB_POINTER) | if (csio->ccb_h.flags & CAM_CDB_POINTER) | ||||
bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); | bcopy(csio->cdb_io.cdb_ptr, &req->CDB.CDB32[0], csio->cdb_len); | ||||
else { | else { | ||||
KASSERT(csio->cdb_len <= IOCDBLEN, | KASSERT(csio->cdb_len <= IOCDBLEN, | ||||
("cdb_len %d is greater than IOCDBLEN but CAM_CDB_POINTER is not set", | ("cdb_len %d is greater than IOCDBLEN but CAM_CDB_POINTER " | ||||
csio->cdb_len)); | "is not set", csio->cdb_len)); | ||||
bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); | bcopy(csio->cdb_io.cdb_bytes, &req->CDB.CDB32[0],csio->cdb_len); | ||||
} | } | ||||
req->IoFlags = htole16(csio->cdb_len); | req->IoFlags = htole16(csio->cdb_len); | ||||
/* | /* | ||||
* Check if EEDP is supported and enabled. If it is then check if the | * Check if EEDP is supported and enabled. If it is then check if the | ||||
* SCSI opcode could be using EEDP. If so, make sure the LUN exists and | * SCSI opcode could be using EEDP. If so, make sure the LUN exists and | ||||
* is formatted for EEDP support. If all of this is true, set CDB up | * is formatted for EEDP support. If all of this is true, set CDB up | ||||
* for EEDP transfer. | * for EEDP transfer. | ||||
*/ | */ | ||||
eedp_flags = op_code_prot[req->CDB.CDB32[0]]; | eedp_flags = op_code_prot[req->CDB.CDB32[0]]; | ||||
if (sc->eedp_enabled && eedp_flags) { | if (sc->eedp_enabled && eedp_flags) { | ||||
SLIST_FOREACH(lun, &targ->luns, lun_link) { | SLIST_FOREACH(lun, &targ->luns, lun_link) { | ||||
if (lun->lun_id == csio->ccb_h.target_lun) { | if (lun->lun_id == csio->ccb_h.target_lun) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if ((lun != NULL) && (lun->eedp_formatted)) { | if ((lun != NULL) && (lun->eedp_formatted)) { | ||||
req->EEDPBlockSize = htole16(lun->eedp_block_size); | req->EEDPBlockSize = htole16(lun->eedp_block_size); | ||||
eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | | eedp_flags |= (MPI2_SCSIIO_EEDPFLAGS_INC_PRI_REFTAG | | ||||
MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | | MPI2_SCSIIO_EEDPFLAGS_CHECK_REFTAG | | ||||
MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); | MPI2_SCSIIO_EEDPFLAGS_CHECK_GUARD); | ||||
if (sc->mpr_flags & MPR_FLAGS_GEN35_IOC) { | |||||
eedp_flags |= | |||||
MPI25_SCSIIO_EEDPFLAGS_APPTAG_DISABLE_MODE; | |||||
} | |||||
req->EEDPFlags = htole16(eedp_flags); | req->EEDPFlags = htole16(eedp_flags); | ||||
/* | /* | ||||
* If CDB less than 32, fill in Primary Ref Tag with | * If CDB less than 32, fill in Primary Ref Tag with | ||||
* low 4 bytes of LBA. If CDB is 32, tag stuff is | * low 4 bytes of LBA. If CDB is 32, tag stuff is | ||||
* already there. Also, set protection bit. FreeBSD | * already there. Also, set protection bit. FreeBSD | ||||
* currently does not support CDBs bigger than 16, but | * currently does not support CDBs bigger than 16, but | ||||
* the code doesn't hurt, and will be here for the | * the code doesn't hurt, and will be here for the | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | #endif | ||||
* If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0) | * If using FP desc type, need to set a bit in IoFlags (SCSI IO is 0) | ||||
* and set descriptor type. | * and set descriptor type. | ||||
*/ | */ | ||||
if (targ->scsi_req_desc_type == | if (targ->scsi_req_desc_type == | ||||
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) { | MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO) { | ||||
req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH; | req->IoFlags |= MPI25_SCSIIO_IOFLAGS_FAST_PATH; | ||||
cm->cm_desc.FastPathSCSIIO.RequestFlags = | cm->cm_desc.FastPathSCSIIO.RequestFlags = | ||||
MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; | MPI25_REQ_DESCRIPT_FLAGS_FAST_PATH_SCSI_IO; | ||||
cm->cm_desc.FastPathSCSIIO.DevHandle = htole16(targ->handle); | if (!sc->atomic_desc_capable) { | ||||
cm->cm_desc.FastPathSCSIIO.DevHandle = | |||||
htole16(targ->handle); | |||||
} | |||||
} else { | } else { | ||||
cm->cm_desc.SCSIIO.RequestFlags = | cm->cm_desc.SCSIIO.RequestFlags = | ||||
MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; | MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO; | ||||
if (!sc->atomic_desc_capable) | |||||
cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle); | cm->cm_desc.SCSIIO.DevHandle = htole16(targ->handle); | ||||
} | } | ||||
#if __FreeBSD_version >= 1000029 | #if __FreeBSD_version >= 1000029 | ||||
callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0, | callout_reset_sbt(&cm->cm_callout, SBT_1MS * ccb->ccb_h.timeout, 0, | ||||
mprsas_scsiio_timeout, cm, 0); | mprsas_scsiio_timeout, cm, 0); | ||||
#else //__FreeBSD_version < 1000029 | #else //__FreeBSD_version < 1000029 | ||||
callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, | callout_reset(&cm->cm_callout, (ccb->ccb_h.timeout * hz) / 1000, | ||||
mprsas_scsiio_timeout, cm); | mprsas_scsiio_timeout, cm); | ||||
▲ Show 20 Lines • Show All 206 Lines • ▼ Show 20 Lines | mpr_sc_failed_io_info(struct mpr_softc *sc, struct ccb_scsiio *csio, | ||||
if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { | if (scsi_state & MPI2_SCSI_STATE_RESPONSE_INFO_VALID) { | ||||
response_info = le32toh(mpi_reply->ResponseInfo); | response_info = le32toh(mpi_reply->ResponseInfo); | ||||
response_bytes = (u8 *)&response_info; | response_bytes = (u8 *)&response_info; | ||||
mpr_response_code(sc,response_bytes[0]); | mpr_response_code(sc,response_bytes[0]); | ||||
} | } | ||||
} | } | ||||
/** mprsas_nvme_trans_status_code | |||||
* | |||||
* Convert Native NVMe command error status to | |||||
* equivalent SCSI error status. | |||||
* | |||||
* Returns appropriate scsi_status | |||||
*/ | |||||
static u8 | |||||
mprsas_nvme_trans_status_code(struct nvme_status nvme_status, | |||||
struct mpr_command *cm) | |||||
{ | |||||
u8 status = MPI2_SCSI_STATUS_GOOD; | |||||
int skey, asc, ascq; | |||||
union ccb *ccb = cm->cm_complete_data; | |||||
int returned_sense_len; | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_ILLEGAL_REQUEST; | |||||
asc = SCSI_ASC_NO_SENSE; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
switch (nvme_status.sct) { | |||||
case NVME_SCT_GENERIC: | |||||
switch (nvme_status.sc) { | |||||
case NVME_SC_SUCCESS: | |||||
status = MPI2_SCSI_STATUS_GOOD; | |||||
skey = SSD_KEY_NO_SENSE; | |||||
asc = SCSI_ASC_NO_SENSE; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_INVALID_OPCODE: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_ILLEGAL_REQUEST; | |||||
asc = SCSI_ASC_ILLEGAL_COMMAND; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_INVALID_FIELD: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_ILLEGAL_REQUEST; | |||||
asc = SCSI_ASC_INVALID_CDB; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_DATA_TRANSFER_ERROR: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_MEDIUM_ERROR; | |||||
asc = SCSI_ASC_NO_SENSE; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_ABORTED_POWER_LOSS: | |||||
status = MPI2_SCSI_STATUS_TASK_ABORTED; | |||||
skey = SSD_KEY_ABORTED_COMMAND; | |||||
asc = SCSI_ASC_WARNING; | |||||
ascq = SCSI_ASCQ_POWER_LOSS_EXPECTED; | |||||
break; | |||||
case NVME_SC_INTERNAL_DEVICE_ERROR: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_HARDWARE_ERROR; | |||||
asc = SCSI_ASC_INTERNAL_TARGET_FAILURE; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_ABORTED_BY_REQUEST: | |||||
case NVME_SC_ABORTED_SQ_DELETION: | |||||
case NVME_SC_ABORTED_FAILED_FUSED: | |||||
case NVME_SC_ABORTED_MISSING_FUSED: | |||||
status = MPI2_SCSI_STATUS_TASK_ABORTED; | |||||
skey = SSD_KEY_ABORTED_COMMAND; | |||||
asc = SCSI_ASC_NO_SENSE; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_INVALID_NAMESPACE_OR_FORMAT: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_ILLEGAL_REQUEST; | |||||
asc = SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID; | |||||
ascq = SCSI_ASCQ_INVALID_LUN_ID; | |||||
break; | |||||
case NVME_SC_LBA_OUT_OF_RANGE: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_ILLEGAL_REQUEST; | |||||
asc = SCSI_ASC_ILLEGAL_BLOCK; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_CAPACITY_EXCEEDED: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_MEDIUM_ERROR; | |||||
asc = SCSI_ASC_NO_SENSE; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_NAMESPACE_NOT_READY: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_NOT_READY; | |||||
asc = SCSI_ASC_LUN_NOT_READY; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
} | |||||
break; | |||||
case NVME_SCT_COMMAND_SPECIFIC: | |||||
switch (nvme_status.sc) { | |||||
case NVME_SC_INVALID_FORMAT: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_ILLEGAL_REQUEST; | |||||
asc = SCSI_ASC_FORMAT_COMMAND_FAILED; | |||||
ascq = SCSI_ASCQ_FORMAT_COMMAND_FAILED; | |||||
break; | |||||
case NVME_SC_CONFLICTING_ATTRIBUTES: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_ILLEGAL_REQUEST; | |||||
asc = SCSI_ASC_INVALID_CDB; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
} | |||||
break; | |||||
case NVME_SCT_MEDIA_ERROR: | |||||
switch (nvme_status.sc) { | |||||
case NVME_SC_WRITE_FAULTS: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_MEDIUM_ERROR; | |||||
asc = SCSI_ASC_PERIPHERAL_DEV_WRITE_FAULT; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_UNRECOVERED_READ_ERROR: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_MEDIUM_ERROR; | |||||
asc = SCSI_ASC_UNRECOVERED_READ_ERROR; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_GUARD_CHECK_ERROR: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_MEDIUM_ERROR; | |||||
asc = SCSI_ASC_LOG_BLOCK_GUARD_CHECK_FAILED; | |||||
ascq = SCSI_ASCQ_LOG_BLOCK_GUARD_CHECK_FAILED; | |||||
break; | |||||
case NVME_SC_APPLICATION_TAG_CHECK_ERROR: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_MEDIUM_ERROR; | |||||
asc = SCSI_ASC_LOG_BLOCK_APPTAG_CHECK_FAILED; | |||||
ascq = SCSI_ASCQ_LOG_BLOCK_APPTAG_CHECK_FAILED; | |||||
break; | |||||
case NVME_SC_REFERENCE_TAG_CHECK_ERROR: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_MEDIUM_ERROR; | |||||
asc = SCSI_ASC_LOG_BLOCK_REFTAG_CHECK_FAILED; | |||||
ascq = SCSI_ASCQ_LOG_BLOCK_REFTAG_CHECK_FAILED; | |||||
break; | |||||
case NVME_SC_COMPARE_FAILURE: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_MISCOMPARE; | |||||
asc = SCSI_ASC_MISCOMPARE_DURING_VERIFY; | |||||
ascq = SCSI_ASCQ_CAUSE_NOT_REPORTABLE; | |||||
break; | |||||
case NVME_SC_ACCESS_DENIED: | |||||
status = MPI2_SCSI_STATUS_CHECK_CONDITION; | |||||
skey = SSD_KEY_ILLEGAL_REQUEST; | |||||
asc = SCSI_ASC_ACCESS_DENIED_INVALID_LUN_ID; | |||||
ascq = SCSI_ASCQ_INVALID_LUN_ID; | |||||
break; | |||||
} | |||||
break; | |||||
} | |||||
returned_sense_len = sizeof(struct scsi_sense_data); | |||||
if (returned_sense_len < ccb->csio.sense_len) | |||||
ccb->csio.sense_resid = ccb->csio.sense_len - | |||||
returned_sense_len; | |||||
else | |||||
ccb->csio.sense_resid = 0; | |||||
scsi_set_sense_data(&ccb->csio.sense_data, SSD_TYPE_FIXED, | |||||
1, skey, asc, ascq, SSD_ELEM_NONE); | |||||
ccb->ccb_h.status |= CAM_AUTOSNS_VALID; | |||||
return status; | |||||
} | |||||
/** mprsas_complete_nvme_unmap | |||||
* | |||||
* Complete native NVMe command issued using NVMe Encapsulated | |||||
* Request Message. | |||||
*/ | |||||
static u8 | |||||
mprsas_complete_nvme_unmap(struct mpr_softc *sc, struct mpr_command *cm) | |||||
{ | |||||
Mpi26NVMeEncapsulatedErrorReply_t *mpi_reply; | |||||
struct nvme_completion *nvme_completion = NULL; | |||||
u8 scsi_status = MPI2_SCSI_STATUS_GOOD; | |||||
mpi_reply =(Mpi26NVMeEncapsulatedErrorReply_t *)cm->cm_reply; | |||||
if (le16toh(mpi_reply->ErrorResponseCount)){ | |||||
nvme_completion = (struct nvme_completion *)cm->cm_sense; | |||||
scsi_status = mprsas_nvme_trans_status_code( | |||||
nvme_completion->status, cm); | |||||
} | |||||
return scsi_status; | |||||
} | |||||
static void | static void | ||||
mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) | mprsas_scsiio_complete(struct mpr_softc *sc, struct mpr_command *cm) | ||||
{ | { | ||||
MPI2_SCSI_IO_REPLY *rep; | MPI2_SCSI_IO_REPLY *rep; | ||||
union ccb *ccb; | union ccb *ccb; | ||||
struct ccb_scsiio *csio; | struct ccb_scsiio *csio; | ||||
struct mprsas_softc *sassc; | struct mprsas_softc *sassc; | ||||
struct scsi_vpd_supported_page_list *vpd_list = NULL; | struct scsi_vpd_supported_page_list *vpd_list = NULL; | ||||
u8 *TLR_bits, TLR_on; | u8 *TLR_bits, TLR_on, *scsi_cdb; | ||||
int dir = 0, i; | int dir = 0, i; | ||||
u16 alloc_len; | u16 alloc_len; | ||||
struct mprsas_target *target; | struct mprsas_target *target; | ||||
target_id_t target_id; | target_id_t target_id; | ||||
MPR_FUNCTRACE(sc); | MPR_FUNCTRACE(sc); | ||||
mpr_dprint(sc, MPR_TRACE, | mpr_dprint(sc, MPR_TRACE, | ||||
"cm %p SMID %u ccb %p reply %p outstanding %u\n", cm, | "cm %p SMID %u ccb %p reply %p outstanding %u\n", cm, | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | if ((sassc->flags & MPRSAS_QUEUE_FROZEN) == 0) { | ||||
xpt_freeze_simq(sassc->sim, 1); | xpt_freeze_simq(sassc->sim, 1); | ||||
sassc->flags |= MPRSAS_QUEUE_FROZEN; | sassc->flags |= MPRSAS_QUEUE_FROZEN; | ||||
mpr_dprint(sc, MPR_INFO, "Error sending command, " | mpr_dprint(sc, MPR_INFO, "Error sending command, " | ||||
"freezing SIM queue\n"); | "freezing SIM queue\n"); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Point to the SCSI CDB, which is dependent on the CAM_CDB_POINTER | |||||
* flag, and use it in a few places in the rest of this function for | |||||
* convenience. Use the macro if available. | |||||
*/ | |||||
#if __FreeBSD_version >= 1100103 | |||||
scsi_cdb = scsiio_cdb_ptr(csio); | |||||
#else | |||||
if (csio->ccb_h.flags & CAM_CDB_POINTER) | |||||
scsi_cdb = csio->cdb_io.cdb_ptr; | |||||
else | |||||
scsi_cdb = csio->cdb_io.cdb_bytes; | |||||
#endif | |||||
/* | |||||
* If this is a Start Stop Unit command and it was issued by the driver | * If this is a Start Stop Unit command and it was issued by the driver | ||||
* during shutdown, decrement the refcount to account for all of the | * during shutdown, decrement the refcount to account for all of the | ||||
* commands that were sent. All SSU commands should be completed before | * commands that were sent. All SSU commands should be completed before | ||||
* shutdown completes, meaning SSU_refcount will be 0 after SSU_started | * shutdown completes, meaning SSU_refcount will be 0 after SSU_started | ||||
* is TRUE. | * is TRUE. | ||||
*/ | */ | ||||
if (sc->SSU_started && (csio->cdb_io.cdb_bytes[0] == START_STOP_UNIT)) { | if (sc->SSU_started && (scsi_cdb[0] == START_STOP_UNIT)) { | ||||
mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n"); | mpr_dprint(sc, MPR_INFO, "Decrementing SSU count.\n"); | ||||
sc->SSU_refcount--; | sc->SSU_refcount--; | ||||
} | } | ||||
/* Take the fast path to completion */ | /* Take the fast path to completion */ | ||||
if (cm->cm_reply == NULL) { | if (cm->cm_reply == NULL) { | ||||
if (mprsas_get_ccbstatus(ccb) == CAM_REQ_INPROG) { | if (mprsas_get_ccbstatus(ccb) == CAM_REQ_INPROG) { | ||||
if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) | if ((sc->mpr_flags & MPR_FLAGS_DIAGRESET) != 0) | ||||
Show All 24 Lines | if (mprsas_get_ccbstatus(ccb) != CAM_REQ_CMP) { | ||||
ccb->ccb_h.status |= CAM_DEV_QFRZN; | ccb->ccb_h.status |= CAM_DEV_QFRZN; | ||||
xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); | xpt_freeze_devq(ccb->ccb_h.path, /*count*/ 1); | ||||
} | } | ||||
mpr_free_command(sc, cm); | mpr_free_command(sc, cm); | ||||
xpt_done(ccb); | xpt_done(ccb); | ||||
return; | return; | ||||
} | } | ||||
target = &sassc->targets[target_id]; | |||||
if (scsi_cdb[0] == UNMAP && | |||||
target->is_nvme && | |||||
(csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) { | |||||
rep->SCSIStatus = mprsas_complete_nvme_unmap(sc, cm); | |||||
csio->scsi_status = rep->SCSIStatus; | |||||
} | |||||
mprsas_log_command(cm, MPR_XINFO, | mprsas_log_command(cm, MPR_XINFO, | ||||
"ioc %x scsi %x state %x xfer %u\n", | "ioc %x scsi %x state %x xfer %u\n", | ||||
le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, | le16toh(rep->IOCStatus), rep->SCSIStatus, rep->SCSIState, | ||||
le32toh(rep->TransferCount)); | le32toh(rep->TransferCount)); | ||||
switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) { | switch (le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) { | ||||
case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: | case MPI2_IOCSTATUS_SCSI_DATA_UNDERRUN: | ||||
csio->resid = cm->cm_length - le32toh(rep->TransferCount); | csio->resid = cm->cm_length - le32toh(rep->TransferCount); | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case MPI2_IOCSTATUS_SUCCESS: | case MPI2_IOCSTATUS_SUCCESS: | ||||
case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: | case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: | ||||
if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) == | if ((le16toh(rep->IOCStatus) & MPI2_IOCSTATUS_MASK) == | ||||
MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR) | MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR) | ||||
mprsas_log_command(cm, MPR_XINFO, "recovered error\n"); | mprsas_log_command(cm, MPR_XINFO, "recovered error\n"); | ||||
/* Completion failed at the transport level. */ | /* Completion failed at the transport level. */ | ||||
if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | | if (rep->SCSIState & (MPI2_SCSI_STATE_NO_SCSI_STATUS | | ||||
MPI2_SCSI_STATE_TERMINATED)) { | MPI2_SCSI_STATE_TERMINATED)) { | ||||
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); | mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | case MPI2_IOCSTATUS_SCSI_RECOVERED_ERROR: | ||||
/* | /* | ||||
* Check if this is an INQUIRY command. If it's a VPD inquiry, | * Check if this is an INQUIRY command. If it's a VPD inquiry, | ||||
* and it's page code 0 (Supported Page List), and there is | * and it's page code 0 (Supported Page List), and there is | ||||
* inquiry data, and this is for a sequential access device, and | * inquiry data, and this is for a sequential access device, and | ||||
* the device is an SSP target, and TLR is supported by the | * the device is an SSP target, and TLR is supported by the | ||||
* controller, turn the TLR_bits value ON if page 0x90 is | * controller, turn the TLR_bits value ON if page 0x90 is | ||||
* supported. | * supported. | ||||
*/ | */ | ||||
if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) && | if ((scsi_cdb[0] == INQUIRY) && | ||||
(csio->cdb_io.cdb_bytes[1] & SI_EVPD) && | (scsi_cdb[1] & SI_EVPD) && | ||||
(csio->cdb_io.cdb_bytes[2] == SVPD_SUPPORTED_PAGE_LIST) && | (scsi_cdb[2] == SVPD_SUPPORTED_PAGE_LIST) && | ||||
((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) && | ((csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) && | ||||
(csio->data_ptr != NULL) && | (csio->data_ptr != NULL) && | ||||
((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) && | ((csio->data_ptr[0] & 0x1f) == T_SEQUENTIAL) && | ||||
(sc->control_TLR) && | (sc->control_TLR) && | ||||
(sc->mapping_table[target_id].device_info & | (sc->mapping_table[target_id].device_info & | ||||
MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { | MPI2_SAS_DEVICE_INFO_SSP_TARGET)) { | ||||
vpd_list = (struct scsi_vpd_supported_page_list *) | vpd_list = (struct scsi_vpd_supported_page_list *) | ||||
csio->data_ptr; | csio->data_ptr; | ||||
TLR_bits = &sc->mapping_table[target_id].TLR_bits; | TLR_bits = &sc->mapping_table[target_id].TLR_bits; | ||||
*TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; | *TLR_bits = (u8)MPI2_SCSIIO_CONTROL_NO_TLR; | ||||
TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; | TLR_on = (u8)MPI2_SCSIIO_CONTROL_TLR_ON; | ||||
alloc_len = ((u16)csio->cdb_io.cdb_bytes[3] << 8) + | alloc_len = ((u16)scsi_cdb[3] << 8) + scsi_cdb[4]; | ||||
csio->cdb_io.cdb_bytes[4]; | |||||
alloc_len -= csio->resid; | alloc_len -= csio->resid; | ||||
for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { | for (i = 0; i < MIN(vpd_list->length, alloc_len); i++) { | ||||
if (vpd_list->list[i] == 0x90) { | if (vpd_list->list[i] == 0x90) { | ||||
*TLR_bits = TLR_on; | *TLR_bits = TLR_on; | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If this is a SATA direct-access end device, mark it so that | * If this is a SATA direct-access end device, mark it so that | ||||
* a SCSI StartStopUnit command will be sent to it when the | * a SCSI StartStopUnit command will be sent to it when the | ||||
* driver is being shutdown. | * driver is being shutdown. | ||||
*/ | */ | ||||
if ((csio->cdb_io.cdb_bytes[0] == INQUIRY) && | if ((scsi_cdb[0] == INQUIRY) && | ||||
(csio->data_ptr != NULL) && | (csio->data_ptr != NULL) && | ||||
((csio->data_ptr[0] & 0x1f) == T_DIRECT) && | ((csio->data_ptr[0] & 0x1f) == T_DIRECT) && | ||||
(sc->mapping_table[target_id].device_info & | (sc->mapping_table[target_id].device_info & | ||||
MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && | MPI2_SAS_DEVICE_INFO_SATA_DEVICE) && | ||||
((sc->mapping_table[target_id].device_info & | ((sc->mapping_table[target_id].device_info & | ||||
MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == | MPI2_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) == | ||||
MPI2_SAS_DEVICE_INFO_END_DEVICE)) { | MPI2_SAS_DEVICE_INFO_END_DEVICE)) { | ||||
target = &sassc->targets[target_id]; | target = &sassc->targets[target_id]; | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | #endif | ||||
case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: | case MPI2_IOCSTATUS_SCSI_TASK_MGMT_FAILED: | ||||
default: | default: | ||||
mprsas_log_command(cm, MPR_XINFO, | mprsas_log_command(cm, MPR_XINFO, | ||||
"completed ioc %x loginfo %x scsi %x state %x xfer %u\n", | "completed ioc %x loginfo %x scsi %x state %x xfer %u\n", | ||||
le16toh(rep->IOCStatus), le32toh(rep->IOCLogInfo), | le16toh(rep->IOCStatus), le32toh(rep->IOCLogInfo), | ||||
rep->SCSIStatus, rep->SCSIState, | rep->SCSIStatus, rep->SCSIState, | ||||
le32toh(rep->TransferCount)); | le32toh(rep->TransferCount)); | ||||
csio->resid = cm->cm_length; | csio->resid = cm->cm_length; | ||||
if (scsi_cdb[0] == UNMAP && | |||||
target->is_nvme && | |||||
(csio->ccb_h.flags & CAM_DATA_MASK) == CAM_DATA_VADDR) | |||||
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP); | |||||
else | |||||
mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); | mprsas_set_ccbstatus(ccb, CAM_REQ_CMP_ERR); | ||||
break; | break; | ||||
} | } | ||||
mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ); | mpr_sc_failed_io_info(sc, csio, rep, cm->cm_targ); | ||||
if (sassc->flags & MPRSAS_QUEUE_FROZEN) { | if (sassc->flags & MPRSAS_QUEUE_FROZEN) { | ||||
ccb->ccb_h.status |= CAM_RELEASE_SIMQ; | ccb->ccb_h.status |= CAM_RELEASE_SIMQ; | ||||
sassc->flags &= ~MPRSAS_QUEUE_FROZEN; | sassc->flags &= ~MPRSAS_QUEUE_FROZEN; | ||||
▲ Show 20 Lines • Show All 1,031 Lines • Show Last 20 Lines |