예제 #1
0
/*
 * Unfortunately, SCIL doesn't cleanly handle retry conditions.
 *  CAM_REQUEUE_REQ works only when no one is using the pass(4) interface.  So
 *  when SCIL denotes an I/O needs to be retried (typically because of mixing
 *  tagged/non-tagged ATA commands, or running out of NCQ slots), we queue
 *  these I/O internally.  Once SCIL completes an I/O to this device, or we get
 *  a ready notification, we will retry the first I/O on the queue.
 *  Unfortunately, SCIL also doesn't cleanly handle starting the new I/O within
 *  the context of the completion handler, so we need to retry these I/O after
 *  the completion handler is done executing.
 */
void
isci_controller_release_queued_ccbs(struct ISCI_CONTROLLER *controller)
{
	struct ISCI_REMOTE_DEVICE *dev;
	struct ccb_hdr *ccb_h;
	uint8_t *ptr;
	int dev_idx;

	KASSERT(mtx_owned(&controller->lock), ("controller lock not owned"));

	controller->release_queued_ccbs = FALSE;
	for (dev_idx = 0;
	     dev_idx < SCI_MAX_REMOTE_DEVICES;
	     dev_idx++) {

		dev = controller->remote_device[dev_idx];
		if (dev != NULL &&
		    dev->release_queued_ccb == TRUE &&
		    dev->queued_ccb_in_progress == NULL) {
			dev->release_queued_ccb = FALSE;
			ccb_h = TAILQ_FIRST(&dev->queued_ccbs);

			if (ccb_h == NULL)
				continue;

			ptr = scsiio_cdb_ptr(&((union ccb *)ccb_h)->csio);
			isci_log_message(1, "ISCI", "release %p %x\n", ccb_h, *ptr);

			dev->queued_ccb_in_progress = (union ccb *)ccb_h;
			isci_io_request_execute_scsi_io(
			    (union ccb *)ccb_h, controller);
		}
	}
}
예제 #2
0
파일: vpo.c 프로젝트: 2trill2spill/freebsd
static void
vpo_action(struct cam_sim *sim, union ccb *ccb)
{
	struct vpo_data *vpo = (struct vpo_data *)sim->softc;

	ppb_assert_locked(device_get_parent(vpo->vpo_dev));
	switch (ccb->ccb_h.func_code) {
	case XPT_SCSI_IO:
	{
		struct ccb_scsiio *csio;

		csio = &ccb->csio;

		if (ccb->ccb_h.flags & CAM_CDB_PHYS) {
			ccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(ccb);
			break;
		}
#ifdef VP0_DEBUG
		device_printf(vpo->vpo_dev, "XPT_SCSI_IO (0x%x) request\n",
		    *scsiio_cdb_ptr(csio));
#endif
		vpo_intr(vpo, csio);

		xpt_done(ccb);

		break;
	}
	case XPT_CALC_GEOMETRY:
	{
		struct	  ccb_calc_geometry *ccg;

		ccg = &ccb->ccg;

#ifdef VP0_DEBUG
		device_printf(vpo->vpo_dev, "XPT_CALC_GEOMETRY (bs=%d,vs=%jd,c=%d,h=%d,spt=%d) request\n",
			ccg->block_size,
			(intmax_t)ccg->volume_size,
			ccg->cylinders,
			ccg->heads,
			ccg->secs_per_track);
#endif

		ccg->heads = 64;
		ccg->secs_per_track = 32;
		ccg->cylinders = ccg->volume_size /
				 (ccg->heads * ccg->secs_per_track);

		ccb->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}
	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
	{

#ifdef VP0_DEBUG
		device_printf(vpo->vpo_dev, "XPT_RESET_BUS request\n");
#endif

		if (vpo->vpo_isplus) {
			if (imm_reset_bus(&vpo->vpo_io)) {
				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
				xpt_done(ccb);
				return;
			}
		} else {
			if (vpoio_reset_bus(&vpo->vpo_io)) {
				ccb->ccb_h.status = CAM_REQ_CMP_ERR;
				xpt_done(ccb);
				return;
			}
		}

		ccb->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}
	case XPT_PATH_INQ:		/* Path routing inquiry */
	{
		struct ccb_pathinq *cpi = &ccb->cpi;

#ifdef VP0_DEBUG
		device_printf(vpo->vpo_dev, "XPT_PATH_INQ request\n");
#endif
		cpi->version_num = 1; /* XXX??? */
		cpi->hba_inquiry = 0;
		cpi->target_sprt = 0;
		cpi->hba_misc = 0;
		cpi->hba_eng_cnt = 0;
		cpi->max_target = 7;
		cpi->max_lun = 0;
		cpi->initiator_id = VP0_INITIATOR;
		cpi->bus_id = sim->bus_id;
		cpi->base_transfer_speed = 93;
		strlcpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strlcpy(cpi->hba_vid, "Iomega", HBA_IDLEN);
		strlcpy(cpi->dev_name, sim->sim_name, DEV_IDLEN);
		cpi->unit_number = sim->unit_number;
		cpi->transport = XPORT_PPB;
		cpi->transport_version = 0;

		cpi->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}
	default:
		ccb->ccb_h.status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	}

	return;
}
예제 #3
0
파일: vpo.c 프로젝트: 2trill2spill/freebsd
/*
 * vpo_intr()
 */
static void
vpo_intr(struct vpo_data *vpo, struct ccb_scsiio *csio)
{
	int errno;	/* error in errno.h */
#ifdef VP0_DEBUG
	int i;
#endif
	uint8_t *ptr;

	ptr = scsiio_cdb_ptr(csio);
	if (vpo->vpo_isplus) {
		errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
			csio->ccb_h.target_id,
			ptr, csio->cdb_len,
			(char *)csio->data_ptr, csio->dxfer_len,
			&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
	} else {
		errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
			csio->ccb_h.target_id,
			ptr, csio->cdb_len,
			(char *)csio->data_ptr, csio->dxfer_len,
			&vpo->vpo_stat, &vpo->vpo_count, &vpo->vpo_error);
	}

#ifdef VP0_DEBUG
	printf("vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
		 errno, vpo->vpo_stat, vpo->vpo_count, vpo->vpo_error);

	/* dump of command */
	for (i=0; i<csio->cdb_len; i++)
		printf("%x ", ((char *)ptr)[i]);

	printf("\n");
#endif

	if (errno) {
		/* connection to ppbus interrupted */
		csio->ccb_h.status = CAM_CMD_TIMEOUT;
		return;
	}

	/* if a timeout occurred, no sense */
	if (vpo->vpo_error) {
		if (vpo->vpo_error != VP0_ESELECT_TIMEOUT)
			device_printf(vpo->vpo_dev, "VP0 error/timeout (%d)\n",
				vpo->vpo_error);

		csio->ccb_h.status = CAM_CMD_TIMEOUT;
		return;
	}

	/* check scsi status */
	if (vpo->vpo_stat != SCSI_STATUS_OK) {
	   csio->scsi_status = vpo->vpo_stat;

	   /* check if we have to sense the drive */
	   if ((vpo->vpo_stat & SCSI_STATUS_CHECK_COND) != 0) {

		vpo->vpo_sense.cmd.opcode = REQUEST_SENSE;
		vpo->vpo_sense.cmd.length = csio->sense_len;
		vpo->vpo_sense.cmd.control = 0;

		if (vpo->vpo_isplus) {
			errno = imm_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
				csio->ccb_h.target_id,
				(char *)&vpo->vpo_sense.cmd,
				sizeof(vpo->vpo_sense.cmd),
				(char *)&csio->sense_data, csio->sense_len,
				&vpo->vpo_sense.stat, &vpo->vpo_sense.count,
				&vpo->vpo_error);
		} else {
			errno = vpoio_do_scsi(&vpo->vpo_io, VP0_INITIATOR,
				csio->ccb_h.target_id,
				(char *)&vpo->vpo_sense.cmd,
				sizeof(vpo->vpo_sense.cmd),
				(char *)&csio->sense_data, csio->sense_len,
				&vpo->vpo_sense.stat, &vpo->vpo_sense.count,
				&vpo->vpo_error);
		}


#ifdef VP0_DEBUG
		printf("(sense) vpo_do_scsi = %d, status = 0x%x, count = %d, vpo_error = %d\n",
			errno, vpo->vpo_sense.stat, vpo->vpo_sense.count, vpo->vpo_error);
#endif

		/* check sense return status */
		if (errno == 0 && vpo->vpo_sense.stat == SCSI_STATUS_OK) {
		   /* sense ok */
		   csio->ccb_h.status = CAM_AUTOSNS_VALID | CAM_SCSI_STATUS_ERROR;
		   csio->sense_resid = csio->sense_len - vpo->vpo_sense.count;

#ifdef VP0_DEBUG
		   /* dump of sense info */
		   printf("(sense) ");
		   for (i=0; i<vpo->vpo_sense.count; i++)
			printf("%x ", ((char *)&csio->sense_data)[i]);
		   printf("\n");
#endif

		} else {
		   /* sense failed */
		   csio->ccb_h.status = CAM_AUTOSENSE_FAIL;
		}
	   } else {
		/* no sense */
		csio->ccb_h.status = CAM_SCSI_STATUS_ERROR;
	   }

	   return;
	}

	csio->resid = csio->dxfer_len - vpo->vpo_count;
	csio->ccb_h.status = CAM_REQ_CMP;
}