示例#1
0
/**
 * @brief This callback method informs the framework user that the remote
 *        device is ready and capable of processing IO requests.
 *
 * @param[in]  controller This parameter specifies the controller object
 *             with which this callback is associated.
 * @param[in]  domain This parameter specifies the domain object with
 *             which this callback is associated.
 * @param[in]  remote_device This parameter specifies the device object with
 *             which this callback is associated.
 *
 * @return none
 */
void
scif_cb_remote_device_ready(SCI_CONTROLLER_HANDLE_T controller,
    SCI_DOMAIN_HANDLE_T domain, SCI_REMOTE_DEVICE_HANDLE_T remote_device)
{
	struct ISCI_REMOTE_DEVICE *isci_remote_device =
	    sci_object_get_association(remote_device);
	struct ISCI_CONTROLLER *isci_controller =
	    sci_object_get_association(controller);
	uint32_t device_index = isci_remote_device->index;

	if (isci_controller->remote_device[device_index] == NULL) {
		/* This new device is now ready, so put it in the controller's
		 *  remote device list so it is visible to CAM.
		 */
		isci_controller->remote_device[device_index] =
		    isci_remote_device;

		if (isci_controller->has_been_scanned) {
			/* The sim object has been scanned at least once
			 *  already.  In that case, create a CCB to instruct
			 *  CAM to rescan this device.
			 * If the sim object has not been scanned, this device
			 *  will get scanned as part of the initial scan.
			 */
			union ccb *ccb = xpt_alloc_ccb_nowait();

			xpt_create_path(&ccb->ccb_h.path, NULL,
			    cam_sim_path(isci_controller->sim),
			    isci_remote_device->index, CAM_LUN_WILDCARD);

			xpt_rescan(ccb);
		}
	}

	isci_remote_device_release_device_queue(isci_remote_device);
}
示例#2
0
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);
		}
	}
}
示例#3
0
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);
		}
	}
}
示例#4
0
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);
}