void isci_io_request_timeout(void *arg) { struct ISCI_IO_REQUEST *request = (struct ISCI_IO_REQUEST *)arg; struct ISCI_REMOTE_DEVICE *remote_device = (struct ISCI_REMOTE_DEVICE *) sci_object_get_association(request->parent.remote_device_handle); struct ISCI_CONTROLLER *controller = remote_device->domain->controller; mtx_lock(&controller->lock); isci_remote_device_reset(remote_device, NULL); mtx_unlock(&controller->lock); }
static void isci_sysctl_reset_remote_devices(struct ISCI_CONTROLLER *controller, uint32_t remote_devices_to_be_reset) { uint32_t i = 0; while (remote_devices_to_be_reset != 0) { if (remote_devices_to_be_reset & 0x1) { struct ISCI_REMOTE_DEVICE *remote_device = controller->remote_device[i]; if (remote_device != NULL) { mtx_lock(&controller->lock); isci_remote_device_reset(remote_device, NULL); mtx_unlock(&controller->lock); } } remote_devices_to_be_reset >>= 1; i++; } }
void isci_action(struct cam_sim *sim, union ccb *ccb) { struct ISCI_CONTROLLER *controller = (struct ISCI_CONTROLLER *)cam_sim_softc(sim); switch ( ccb->ccb_h.func_code ) { case XPT_PATH_INQ: { struct ccb_pathinq *cpi = &ccb->cpi; int bus = cam_sim_bus(sim); ccb->ccb_h.ccb_sim_ptr = sim; cpi->version_num = 1; cpi->hba_inquiry = PI_TAG_ABLE; cpi->target_sprt = 0; cpi->hba_misc = PIM_NOBUSRESET | PIM_SEQSCAN; cpi->hba_eng_cnt = 0; cpi->max_target = SCI_MAX_REMOTE_DEVICES - 1; cpi->max_lun = ISCI_MAX_LUN; #if __FreeBSD_version >= 800102 cpi->maxio = isci_io_request_get_max_io_size(); #endif cpi->unit_number = cam_sim_unit(sim); cpi->bus_id = bus; cpi->initiator_id = SCI_MAX_REMOTE_DEVICES; cpi->base_transfer_speed = 300000; strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN); strncpy(cpi->hba_vid, "Intel Corp.", HBA_IDLEN); strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN); cpi->transport = XPORT_SAS; cpi->transport_version = 0; cpi->protocol = PROTO_SCSI; cpi->protocol_version = SCSI_REV_SPC2; cpi->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); } break; case XPT_GET_TRAN_SETTINGS: { struct ccb_trans_settings *general_settings = &ccb->cts; struct ccb_trans_settings_sas *sas_settings = &general_settings->xport_specific.sas; struct ccb_trans_settings_scsi *scsi_settings = &general_settings->proto_specific.scsi; struct ISCI_REMOTE_DEVICE *remote_device; remote_device = controller->remote_device[ccb->ccb_h.target_id]; if (remote_device == NULL) { ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_DEV_NOT_THERE; xpt_done(ccb); break; } general_settings->protocol = PROTO_SCSI; general_settings->transport = XPORT_SAS; general_settings->protocol_version = SCSI_REV_SPC2; general_settings->transport_version = 0; scsi_settings->valid = CTS_SCSI_VALID_TQ; scsi_settings->flags = CTS_SCSI_FLAGS_TAG_ENB; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQ_CMP; sas_settings->bitrate = isci_remote_device_get_bitrate(remote_device); if (sas_settings->bitrate != 0) sas_settings->valid = CTS_SAS_VALID_SPEED; xpt_done(ccb); } break; case XPT_SCSI_IO: isci_io_request_execute_scsi_io(ccb, controller); break; #if __FreeBSD_version >= 900026 case XPT_SMP_IO: isci_io_request_execute_smp_io(ccb, controller); break; #endif case XPT_SET_TRAN_SETTINGS: ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQ_CMP; xpt_done(ccb); break; case XPT_CALC_GEOMETRY: cam_calc_geometry(&ccb->ccg, /*extended*/1); xpt_done(ccb); break; case XPT_RESET_DEV: { struct ISCI_REMOTE_DEVICE *remote_device = controller->remote_device[ccb->ccb_h.target_id]; if (remote_device != NULL) isci_remote_device_reset(remote_device, ccb); else { ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_DEV_NOT_THERE; xpt_done(ccb); } } break; case XPT_RESET_BUS: ccb->ccb_h.status = CAM_REQ_CMP; xpt_done(ccb); break; default: isci_log_message(0, "ISCI", "Unhandled func_code 0x%x\n", ccb->ccb_h.func_code); ccb->ccb_h.status &= ~CAM_SIM_QUEUED; ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQ_INVALID; xpt_done(ccb); break; } }
void isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, struct ISCI_IO_REQUEST *isci_request, SCI_IO_STATUS completion_status) { struct ISCI_CONTROLLER *isci_controller; struct ISCI_REMOTE_DEVICE *isci_remote_device; union ccb *ccb; BOOL complete_ccb; complete_ccb = TRUE; isci_controller = (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller); isci_remote_device = (struct ISCI_REMOTE_DEVICE *) sci_object_get_association(remote_device); ccb = isci_request->ccb; ccb->ccb_h.status &= ~CAM_STATUS_MASK; switch (completion_status) { case SCI_IO_SUCCESS: case SCI_IO_SUCCESS_COMPLETE_BEFORE_START: #if __FreeBSD_version >= 900026 if (ccb->ccb_h.func_code == XPT_SMP_IO) { void *smp_response = scif_io_request_get_response_iu_address( isci_request->sci_object); memcpy(ccb->smpio.smp_response, smp_response, ccb->smpio.smp_response_len); } #endif ccb->ccb_h.status |= CAM_REQ_CMP; break; case SCI_IO_SUCCESS_IO_DONE_EARLY: ccb->ccb_h.status |= CAM_REQ_CMP; ccb->csio.resid = ccb->csio.dxfer_len - scif_io_request_get_number_of_bytes_transferred( isci_request->sci_object); break; case SCI_IO_FAILURE_RESPONSE_VALID: { SCI_SSP_RESPONSE_IU_T * response_buffer; uint32_t sense_length; int error_code, sense_key, asc, ascq; struct ccb_scsiio *csio = &ccb->csio; response_buffer = (SCI_SSP_RESPONSE_IU_T *) scif_io_request_get_response_iu_address( isci_request->sci_object); sense_length = sci_ssp_get_sense_data_length( response_buffer->sense_data_length); sense_length = MIN(csio->sense_len, sense_length); memcpy(&csio->sense_data, response_buffer->data, sense_length); csio->sense_resid = csio->sense_len - sense_length; csio->scsi_status = response_buffer->status; ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; ccb->ccb_h.status |= CAM_AUTOSNS_VALID; scsi_extract_sense( &csio->sense_data, &error_code, &sense_key, &asc, &ascq ); isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x status=%x key=%x asc=%x ascq=%x\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0], csio->scsi_status, sense_key, asc, ascq); break; } case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: isci_remote_device_reset(isci_remote_device, NULL); /* drop through */ case SCI_IO_FAILURE_TERMINATED: ccb->ccb_h.status |= CAM_REQ_TERMIO; isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x terminated\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]); break; case SCI_IO_FAILURE_INVALID_STATE: case SCI_IO_FAILURE_INSUFFICIENT_RESOURCES: complete_ccb = FALSE; break; case SCI_IO_FAILURE_INVALID_REMOTE_DEVICE: ccb->ccb_h.status |= CAM_DEV_NOT_THERE; break; case SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE: { struct ccb_relsim ccb_relsim; struct cam_path *path; xpt_create_path(&path, NULL, cam_sim_path(isci_controller->sim), isci_remote_device->index, 0); xpt_setup_ccb(&ccb_relsim.ccb_h, path, 5); ccb_relsim.ccb_h.func_code = XPT_REL_SIMQ; ccb_relsim.ccb_h.flags = CAM_DEV_QFREEZE; ccb_relsim.release_flags = RELSIM_ADJUST_OPENINGS; ccb_relsim.openings = scif_remote_device_get_max_queue_depth(remote_device); xpt_action((union ccb *)&ccb_relsim); xpt_free_path(path); complete_ccb = FALSE; } break; case SCI_IO_FAILURE: case SCI_IO_FAILURE_REQUIRES_SCSI_ABORT: case SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL: case SCI_IO_FAILURE_PROTOCOL_VIOLATION: case SCI_IO_FAILURE_INVALID_PARAMETER_VALUE: case SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR: default: isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x completion status=%x\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0], completion_status); ccb->ccb_h.status |= CAM_REQ_CMP_ERR; break; } callout_stop(&isci_request->parent.timer); bus_dmamap_sync(isci_request->parent.dma_tag, isci_request->parent.dma_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(isci_request->parent.dma_tag, isci_request->parent.dma_map); isci_request->ccb = NULL; sci_pool_put(isci_controller->request_pool, (struct ISCI_REQUEST *)isci_request); if (complete_ccb) { if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { /* ccb will be completed with some type of non-success * status. So temporarily freeze the queue until the * upper layers can act on the status. The * CAM_DEV_QFRZN flag will then release the queue * after the status is acted upon. */ ccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(ccb->ccb_h.path, 1); } if (ccb->ccb_h.status & CAM_SIM_QUEUED) { KASSERT(ccb == isci_remote_device->queued_ccb_in_progress, ("multiple internally queued ccbs in flight")); TAILQ_REMOVE(&isci_remote_device->queued_ccbs, &ccb->ccb_h, sim_links.tqe); ccb->ccb_h.status &= ~CAM_SIM_QUEUED; /* * This CCB that was in the queue was completed, so * set the in_progress pointer to NULL denoting that * we can retry another CCB from the queue. We only * allow one CCB at a time from the queue to be * in progress so that we can effectively maintain * ordering. */ isci_remote_device->queued_ccb_in_progress = NULL; } if (isci_remote_device->frozen_lun_mask != 0) { isci_remote_device_release_device_queue(isci_remote_device); } xpt_done(ccb); if (isci_controller->is_frozen == TRUE) { isci_controller->is_frozen = FALSE; xpt_release_simq(isci_controller->sim, TRUE); } } else { isci_remote_device_freeze_lun_queue(isci_remote_device, ccb->ccb_h.target_lun); if (ccb->ccb_h.status & CAM_SIM_QUEUED) { KASSERT(ccb == isci_remote_device->queued_ccb_in_progress, ("multiple internally queued ccbs in flight")); /* * Do nothing, CCB is already on the device's queue. * We leave it on the queue, to be retried again * next time a CCB on this device completes, or we * get a ready notification for this device. */ isci_log_message(1, "ISCI", "already queued %p %x\n", ccb, ccb->csio.cdb_io.cdb_bytes[0]); isci_remote_device->queued_ccb_in_progress = NULL; } else { isci_log_message(1, "ISCI", "queue %p %x\n", ccb, ccb->csio.cdb_io.cdb_bytes[0]); ccb->ccb_h.status |= CAM_SIM_QUEUED; TAILQ_INSERT_TAIL(&isci_remote_device->queued_ccbs, &ccb->ccb_h, sim_links.tqe); } } }
void isci_task_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, SCI_TASK_REQUEST_HANDLE_T task_request, SCI_TASK_STATUS completion_status) { struct ISCI_TASK_REQUEST *isci_task_request = (struct ISCI_TASK_REQUEST *)sci_object_get_association(task_request); struct ISCI_CONTROLLER *isci_controller = (struct ISCI_CONTROLLER *)sci_object_get_association(scif_controller); struct ISCI_REMOTE_DEVICE *isci_remote_device = (struct ISCI_REMOTE_DEVICE *)sci_object_get_association(remote_device); struct ISCI_REMOTE_DEVICE *pending_remote_device; BOOL retry_task = FALSE; union ccb *ccb = isci_task_request->ccb; isci_remote_device->is_resetting = FALSE; switch ((int)completion_status) { case SCI_TASK_SUCCESS: case SCI_TASK_FAILURE_RESPONSE_VALID: break; case SCI_TASK_FAILURE_INVALID_STATE: retry_task = TRUE; isci_log_message(0, "ISCI", "task failure (invalid state) - retrying\n"); break; case SCI_TASK_FAILURE_INSUFFICIENT_RESOURCES: retry_task = TRUE; isci_log_message(0, "ISCI", "task failure (insufficient resources) - retrying\n"); break; case SCI_FAILURE_TIMEOUT: if (isci_controller->fail_on_task_timeout) { retry_task = FALSE; isci_log_message(0, "ISCI", "task timeout - not retrying\n"); scif_cb_domain_device_removed(isci_controller, isci_remote_device->domain, isci_remote_device); } else { retry_task = TRUE; isci_log_message(0, "ISCI", "task timeout - retrying\n"); } break; case SCI_TASK_FAILURE: case SCI_TASK_FAILURE_UNSUPPORTED_PROTOCOL: case SCI_TASK_FAILURE_INVALID_TAG: case SCI_TASK_FAILURE_CONTROLLER_SPECIFIC_ERR: case SCI_TASK_FAILURE_TERMINATED: case SCI_TASK_FAILURE_INVALID_PARAMETER_VALUE: isci_log_message(0, "ISCI", "unhandled task completion code 0x%x\n", completion_status); break; default: isci_log_message(0, "ISCI", "unhandled task completion code 0x%x\n", completion_status); break; } if (isci_controller->is_frozen == TRUE) { isci_controller->is_frozen = FALSE; xpt_release_simq(isci_controller->sim, TRUE); } sci_pool_put(isci_controller->request_pool, (struct ISCI_REQUEST *)isci_task_request); /* Make sure we release the device queue, since it may have been frozen * if someone tried to start an I/O while the task was in progress. */ isci_remote_device_release_device_queue(isci_remote_device); if (retry_task == TRUE) isci_remote_device_reset(isci_remote_device, ccb); else { pending_remote_device = sci_fast_list_remove_head( &isci_controller->pending_device_reset_list); if (pending_remote_device != NULL) { /* Any resets that were triggered from an XPT_RESET_DEV * CCB are never put in the pending list if the request * pool is empty - they are given back to CAM to be * requeued. So we will alawys pass NULL here, * denoting that there is no CCB associated with the * device reset. */ isci_remote_device_reset(pending_remote_device, NULL); } else if (ccb != NULL) { /* There was a CCB associated with this reset, so mark * it complete and return it to CAM. */ ccb->ccb_h.status &= ~CAM_STATUS_MASK; ccb->ccb_h.status |= CAM_REQ_CMP; xpt_done(ccb); } } }
void isci_io_request_complete(SCI_CONTROLLER_HANDLE_T scif_controller, SCI_REMOTE_DEVICE_HANDLE_T remote_device, struct ISCI_IO_REQUEST *isci_request, SCI_IO_STATUS completion_status) { struct ISCI_CONTROLLER *isci_controller; struct ISCI_REMOTE_DEVICE *isci_remote_device; union ccb *ccb; isci_controller = (struct ISCI_CONTROLLER *) sci_object_get_association(scif_controller); isci_remote_device = (struct ISCI_REMOTE_DEVICE *) sci_object_get_association(remote_device); ccb = isci_request->ccb; ccb->ccb_h.status &= ~CAM_STATUS_MASK; switch (completion_status) { case SCI_IO_SUCCESS: case SCI_IO_SUCCESS_COMPLETE_BEFORE_START: #if __FreeBSD_version >= 900026 if (ccb->ccb_h.func_code == XPT_SMP_IO) { void *smp_response = scif_io_request_get_response_iu_address( isci_request->sci_object); memcpy(ccb->smpio.smp_response, smp_response, ccb->smpio.smp_response_len); } #endif ccb->ccb_h.status |= CAM_REQ_CMP; break; case SCI_IO_SUCCESS_IO_DONE_EARLY: ccb->ccb_h.status |= CAM_REQ_CMP; ccb->csio.resid = ccb->csio.dxfer_len - scif_io_request_get_number_of_bytes_transferred( isci_request->sci_object); break; case SCI_IO_FAILURE_RESPONSE_VALID: { SCI_SSP_RESPONSE_IU_T * response_buffer; uint32_t sense_length; int error_code, sense_key, asc, ascq; struct ccb_scsiio *csio = &ccb->csio; response_buffer = (SCI_SSP_RESPONSE_IU_T *) scif_io_request_get_response_iu_address( isci_request->sci_object); sense_length = sci_ssp_get_sense_data_length( response_buffer->sense_data_length); sense_length = MIN(csio->sense_len, sense_length); memcpy(&csio->sense_data, response_buffer->data, sense_length); csio->sense_resid = csio->sense_len - sense_length; csio->scsi_status = response_buffer->status; ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR; ccb->ccb_h.status |= CAM_AUTOSNS_VALID; scsi_extract_sense( &csio->sense_data, &error_code, &sense_key, &asc, &ascq ); isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x status=%x key=%x asc=%x ascq=%x\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, csio->cdb_io.cdb_bytes[0], csio->scsi_status, sense_key, asc, ascq); break; } case SCI_IO_FAILURE_REMOTE_DEVICE_RESET_REQUIRED: isci_remote_device_reset(isci_remote_device, NULL); /* drop through */ case SCI_IO_FAILURE_TERMINATED: ccb->ccb_h.status |= CAM_REQ_TERMIO; isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x terminated\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0]); break; case SCI_IO_FAILURE_INVALID_STATE: case SCI_IO_FAILURE_INSUFFICIENT_RESOURCES: ccb->ccb_h.status |= CAM_REQUEUE_REQ; isci_remote_device_freeze_lun_queue(isci_remote_device, ccb->ccb_h.target_lun); break; case SCI_IO_FAILURE_INVALID_REMOTE_DEVICE: ccb->ccb_h.status |= CAM_DEV_NOT_THERE; break; case SCI_IO_FAILURE_NO_NCQ_TAG_AVAILABLE: { struct ccb_relsim ccb_relsim; struct cam_path *path; xpt_create_path(&path, NULL, cam_sim_path(isci_controller->sim), isci_remote_device->index, 0); xpt_setup_ccb(&ccb_relsim.ccb_h, path, 5); ccb_relsim.ccb_h.func_code = XPT_REL_SIMQ; ccb_relsim.ccb_h.flags = CAM_DEV_QFREEZE; ccb_relsim.release_flags = RELSIM_ADJUST_OPENINGS; ccb_relsim.openings = scif_remote_device_get_max_queue_depth(remote_device); xpt_action((union ccb *)&ccb_relsim); xpt_free_path(path); ccb->ccb_h.status |= CAM_REQUEUE_REQ; } break; case SCI_IO_FAILURE: case SCI_IO_FAILURE_REQUIRES_SCSI_ABORT: case SCI_IO_FAILURE_UNSUPPORTED_PROTOCOL: case SCI_IO_FAILURE_PROTOCOL_VIOLATION: case SCI_IO_FAILURE_INVALID_PARAMETER_VALUE: case SCI_IO_FAILURE_CONTROLLER_SPECIFIC_ERR: default: isci_log_message(1, "ISCI", "isci: bus=%x target=%x lun=%x cdb[0]=%x completion status=%x\n", ccb->ccb_h.path_id, ccb->ccb_h.target_id, ccb->ccb_h.target_lun, ccb->csio.cdb_io.cdb_bytes[0], completion_status); ccb->ccb_h.status |= CAM_REQ_CMP_ERR; break; } if (ccb->ccb_h.status != CAM_REQ_CMP) { /* ccb will be completed with some type of non-success * status. So temporarily freeze the queue until the * upper layers can act on the status. The CAM_DEV_QFRZN * flag will then release the queue after the status is * acted upon. */ ccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(ccb->ccb_h.path, 1); } callout_stop(&isci_request->parent.timer); bus_dmamap_sync(isci_request->parent.dma_tag, isci_request->parent.dma_map, BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); bus_dmamap_unload(isci_request->parent.dma_tag, isci_request->parent.dma_map); if (isci_remote_device->frozen_lun_mask != 0 && !(ccb->ccb_h.status & CAM_REQUEUE_REQ)) isci_remote_device_release_device_queue(isci_remote_device); xpt_done(ccb); isci_request->ccb = NULL; if (isci_controller->is_frozen == TRUE) { isci_controller->is_frozen = FALSE; xpt_release_simq(isci_controller->sim, TRUE); } sci_pool_put(isci_controller->request_pool, (struct ISCI_REQUEST *)isci_request); }