Esempio n. 1
0
static void
cfcs_done(union ctl_io *io)
{
	union ccb *ccb;

	ccb = io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr;
	if (ccb == NULL) {
		ctl_free_io(io);
		return;
	}

	/*
	 * At this point we should have status.  If we don't, that's a bug.
	 */
	KASSERT(((io->io_hdr.status & CTL_STATUS_MASK) != CTL_STATUS_NONE),
		("invalid CTL status %#x", io->io_hdr.status));

	/*
	 * Translate CTL status to CAM status.
	 */
	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
	switch (io->io_hdr.status & CTL_STATUS_MASK) {
	case CTL_SUCCESS:
		ccb->ccb_h.status |= CAM_REQ_CMP;
		break;
	case CTL_SCSI_ERROR:
		ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR | CAM_AUTOSNS_VALID;
		ccb->csio.scsi_status = io->scsiio.scsi_status;
		bcopy(&io->scsiio.sense_data, &ccb->csio.sense_data,
		      min(io->scsiio.sense_len, ccb->csio.sense_len));
		if (ccb->csio.sense_len > io->scsiio.sense_len)
			ccb->csio.sense_resid = ccb->csio.sense_len -
						io->scsiio.sense_len;
		else
			ccb->csio.sense_resid = 0;
		if ((ccb->csio.sense_len - ccb->csio.sense_resid) >
		     cfcs_max_sense) {
			ccb->csio.sense_resid = ccb->csio.sense_len -
						cfcs_max_sense;
		}
		break;
	case CTL_CMD_ABORTED:
		ccb->ccb_h.status |= CAM_REQ_ABORTED;
		break;
	case CTL_ERROR:
	default:
		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
		break;
	}
	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP &&
	    (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
		xpt_freeze_devq(ccb->ccb_h.path, 1);
		ccb->ccb_h.status |= CAM_DEV_QFRZN;
	}
	xpt_done(ccb);
	ctl_free_io(io);
}
Esempio n. 2
0
void
isci_remote_device_freeze_lun_queue(struct ISCI_REMOTE_DEVICE *remote_device,
    lun_id_t lun)
{
	if (!(remote_device->frozen_lun_mask & (1 << lun))) {
		struct cam_path *path;

		xpt_create_path(&path, NULL,
		    cam_sim_path(remote_device->domain->controller->sim),
		    remote_device->index, lun);
		xpt_freeze_devq(path, 1);
		xpt_free_path(path);
		remote_device->frozen_lun_mask |= (1 << lun);
	}
}
Esempio n. 3
0
void
isp_done(struct ccb_scsiio *sccb)
{
	struct ispsoftc *isp = XS_ISP(sccb);

	if (XS_NOERR(sccb))
		XS_SETERR(sccb, CAM_REQ_CMP);
	sccb->ccb_h.status &= ~CAM_STATUS_MASK;
	sccb->ccb_h.status |= sccb->ccb_h.spriv_field0;
	if ((sccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP &&
	    (sccb->scsi_status != SCSI_STATUS_OK)) {
		sccb->ccb_h.status &= ~CAM_STATUS_MASK;
		sccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
	}
	if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
		if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
			IDPRINTF(3, ("%s: freeze devq %d.%d ccbstat 0x%x\n",
			    isp->isp_name, sccb->ccb_h.target_id,
			    sccb->ccb_h.target_lun, sccb->ccb_h.status));
			xpt_freeze_devq(sccb->ccb_h.path, 1);
			sccb->ccb_h.status |= CAM_DEV_QFRZN;
		}
	}
	if (isp->isp_osinfo.simqfrozen & SIMQFRZ_RESOURCE) {
		isp->isp_osinfo.simqfrozen &= ~SIMQFRZ_RESOURCE;
		sccb->ccb_h.status |= CAM_RELEASE_SIMQ;
		xpt_release_simq(isp->isp_sim, 1);
	}
	sccb->ccb_h.status &= ~CAM_SIM_QUEUED;
	if (CAM_DEBUGGED(sccb->ccb_h.path, ISPDDB) &&
	    (sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) {
		xpt_print_path(sccb->ccb_h.path);
		printf("cam completion status 0x%x\n", sccb->ccb_h.status);
	}
	xpt_done((union ccb *) sccb);
}
Esempio n. 4
0
static void
ata_cam_end_transaction(device_t dev, struct ata_request *request)
{
	struct ata_channel *ch = device_get_softc(dev);
	union ccb *ccb = request->ccb;
	int fatalerr = 0;

	if (ch->requestsense) {
		ata_cam_process_sense(dev, request);
		return;
	}

	ccb->ccb_h.status &= ~CAM_STATUS_MASK;
	if (request->flags & ATA_R_TIMEOUT) {
		xpt_freeze_simq(ch->sim, 1);
		ccb->ccb_h.status &= ~CAM_STATUS_MASK;
		ccb->ccb_h.status |= CAM_CMD_TIMEOUT | CAM_RELEASE_SIMQ;
		fatalerr = 1;
	} else if (request->status & ATA_S_ERROR) {
		if (ccb->ccb_h.func_code == XPT_ATA_IO) {
			ccb->ccb_h.status |= CAM_ATA_STATUS_ERROR;
		} else {
			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
			ccb->csio.scsi_status = SCSI_STATUS_CHECK_COND;
		}
	} else if (request->result == ERESTART)
		ccb->ccb_h.status |= CAM_REQUEUE_REQ;
	else if (request->result != 0)
		ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
	else
		ccb->ccb_h.status |= CAM_REQ_CMP;
	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP &&
	    !(ccb->ccb_h.status & CAM_DEV_QFRZN)) {
		xpt_freeze_devq(ccb->ccb_h.path, 1);
		ccb->ccb_h.status |= CAM_DEV_QFRZN;
	}
	if (ccb->ccb_h.func_code == XPT_ATA_IO &&
	    ((request->status & ATA_S_ERROR) ||
	    (ccb->ataio.cmd.flags & CAM_ATAIO_NEEDRESULT))) {
		struct ata_res *res = &ccb->ataio.res;
		res->status = request->status;
		res->error = request->error;
		res->lba_low = request->u.ata.lba;
		res->lba_mid = request->u.ata.lba >> 8;
		res->lba_high = request->u.ata.lba >> 16;
		res->device = request->u.ata.lba >> 24;
		res->lba_low_exp = request->u.ata.lba >> 24;
		res->lba_mid_exp = request->u.ata.lba >> 32;
		res->lba_high_exp = request->u.ata.lba >> 40;
		res->sector_count = request->u.ata.count;
		res->sector_count_exp = request->u.ata.count >> 8;
	}
	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
		if (ccb->ccb_h.func_code == XPT_ATA_IO) {
			ccb->ataio.resid =
			    ccb->ataio.dxfer_len - request->donecount;
		} else {
			ccb->csio.resid =
			    ccb->csio.dxfer_len - request->donecount;
		}
	}
	if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_SCSI_STATUS_ERROR &&
	    (ccb->ccb_h.flags & CAM_DIS_AUTOSENSE) == 0)
		ata_cam_request_sense(dev, request);
	else {
		ata_free_request(request);
		xpt_done(ccb);
	}
	/* Do error recovery if needed. */
	if (fatalerr)
		ata_reinit(dev);
}
Esempio n. 5
0
void
adv_done(struct adv_softc *adv, union ccb *ccb, u_int done_stat,
	 u_int host_stat, u_int scsi_status, u_int q_no)
{
	struct	   adv_ccb_info *cinfo;

	cinfo = (struct adv_ccb_info *)ccb->ccb_h.ccb_cinfo_ptr;
	LIST_REMOVE(&ccb->ccb_h, sim_links.le);
	untimeout(adv_timeout, ccb, ccb->ccb_h.timeout_ch);
	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
		bus_dmasync_op_t op;

		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
			op = BUS_DMASYNC_POSTREAD;
		else
			op = BUS_DMASYNC_POSTWRITE;
		bus_dmamap_sync(adv->buffer_dmat, cinfo->dmamap, op);
		bus_dmamap_unload(adv->buffer_dmat, cinfo->dmamap);
	}

	switch (done_stat) {
	case QD_NO_ERROR:
		if (host_stat == QHSTA_NO_ERROR) {
			ccb->ccb_h.status = CAM_REQ_CMP;
			break;
		}
		xpt_print_path(ccb->ccb_h.path);
		printf("adv_done - queue done without error, "
		       "but host status non-zero(%x)\n", host_stat);
		/*FALLTHROUGH*/
	case QD_WITH_ERROR:
		switch (host_stat) {
		case QHSTA_M_TARGET_STATUS_BUSY:
		case QHSTA_M_BAD_QUEUE_FULL_OR_BUSY:
			/*
			 * Assume that if we were a tagged transaction
			 * the target reported queue full.  Otherwise,
			 * report busy.  The firmware really should just
			 * pass the original status back up to us even
			 * if it thinks the target was in error for
			 * returning this status as no other transactions
			 * from this initiator are in effect, but this
			 * ignores multi-initiator setups and there is
			 * evidence that the firmware gets its per-device
			 * transaction counts screwed up occassionally.
			 */
			ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
			if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0
			 && host_stat != QHSTA_M_TARGET_STATUS_BUSY)
				scsi_status = SCSI_STATUS_QUEUE_FULL;
			else
				scsi_status = SCSI_STATUS_BUSY;
			adv_abort_ccb(adv, ccb->ccb_h.target_id,
				      ccb->ccb_h.target_lun,
				      /*ccb*/NULL, CAM_REQUEUE_REQ,
				      /*queued_only*/TRUE);
			/*FALLTHROUGH*/
		case QHSTA_M_NO_AUTO_REQ_SENSE:
		case QHSTA_NO_ERROR:
			ccb->csio.scsi_status = scsi_status;
			switch (scsi_status) {
			case SCSI_STATUS_CHECK_COND:
			case SCSI_STATUS_CMD_TERMINATED:
				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
				/* Structure copy */
				ccb->csio.sense_data =
				    adv->sense_buffers[q_no - 1];
				/* FALLTHROUGH */
			case SCSI_STATUS_BUSY:
			case SCSI_STATUS_RESERV_CONFLICT:
			case SCSI_STATUS_QUEUE_FULL:
			case SCSI_STATUS_COND_MET:
			case SCSI_STATUS_INTERMED:
			case SCSI_STATUS_INTERMED_COND_MET:
				ccb->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
				break;
			case SCSI_STATUS_OK:
				ccb->ccb_h.status |= CAM_REQ_CMP;
				break;
			}
			break;
		case QHSTA_M_SEL_TIMEOUT:
			ccb->ccb_h.status = CAM_SEL_TIMEOUT;
			break;
		case QHSTA_M_DATA_OVER_RUN:
			ccb->ccb_h.status = CAM_DATA_RUN_ERR;
			break;
		case QHSTA_M_UNEXPECTED_BUS_FREE:
			ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
			break;
		case QHSTA_M_BAD_BUS_PHASE_SEQ:
			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
			break;
		case QHSTA_M_BAD_CMPL_STATUS_IN:
			/* No command complete after a status message */
			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
			break;
		case QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT:
		case QHSTA_M_WTM_TIMEOUT:
		case QHSTA_M_HUNG_REQ_SCSI_BUS_RESET:
			/* The SCSI bus hung in a phase */
			ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
			adv_reset_bus(adv, /*initiate_reset*/TRUE);
			break;
		case QHSTA_M_AUTO_REQ_SENSE_FAIL:
			ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
			break;
		case QHSTA_D_QDONE_SG_LIST_CORRUPTED:
		case QHSTA_D_ASC_DVC_ERROR_CODE_SET:
		case QHSTA_D_HOST_ABORT_FAILED:
		case QHSTA_D_EXE_SCSI_Q_FAILED:
		case QHSTA_D_ASPI_NO_BUF_POOL:
		case QHSTA_M_BAD_TAG_CODE:
		case QHSTA_D_LRAM_CMP_ERROR:
		case QHSTA_M_MICRO_CODE_ERROR_HALT:
		default:
			panic("%s: Unhandled Host status error %x",
			      adv_name(adv), host_stat);
			/* NOTREACHED */
		}
		break;

	case QD_ABORTED_BY_HOST:
		/* Don't clobber any, more explicit, error codes we've set */
		if ((ccb->ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_INPROG)
			ccb->ccb_h.status = CAM_REQ_ABORTED;
		break;

	default:
		xpt_print_path(ccb->ccb_h.path);
		printf("adv_done - queue done with unknown status %x:%x\n",
		       done_stat, host_stat);
		ccb->ccb_h.status = CAM_REQ_CMP_ERR;
		break;
	}
	adv_clear_state(adv, ccb);
	if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP
	 && (ccb->ccb_h.status & CAM_DEV_QFRZN) == 0) {
		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
		ccb->ccb_h.status |= CAM_DEV_QFRZN;
	}
	adv_free_ccb_info(adv, cinfo);
	/*
	 * Null this out so that we catch driver bugs that cause a
	 * ccb to be completed twice.
	 */
	ccb->ccb_h.ccb_cinfo_ptr = NULL;
	ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
	xpt_done(ccb);
}
Esempio n. 6
0
void
cfcs_action(struct cam_sim *sim, union ccb *ccb)
{
	struct cfcs_softc *softc;
	int err;

	softc = (struct cfcs_softc *)cam_sim_softc(sim);
	mtx_assert(&softc->lock, MA_OWNED);

	switch (ccb->ccb_h.func_code) {
	case XPT_SCSI_IO: {
		union ctl_io *io;
		struct ccb_scsiio *csio;

		csio = &ccb->csio;

		/*
		 * Catch CCB flags, like physical address flags, that
	 	 * indicate situations we currently can't handle.
		 */
		if (ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS) {
			ccb->ccb_h.status = CAM_REQ_INVALID;
			printf("%s: bad CCB flags %#x (all flags %#x)\n",
			       __func__, ccb->ccb_h.flags & CFCS_BAD_CCB_FLAGS,
			       ccb->ccb_h.flags);
			xpt_done(ccb);
			return;
		}

		/*
		 * If we aren't online, there are no devices to see.
		 */
		if (softc->online == 0) {
			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
			xpt_done(ccb);
			return;
		}

		io = ctl_alloc_io(softc->fe.ctl_pool_ref);
		if (io == NULL) {
			printf("%s: can't allocate ctl_io\n", __func__);
			ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
			xpt_freeze_devq(ccb->ccb_h.path, 1);
			xpt_done(ccb);
			return;
		}
		ctl_zero_io(io);
		/* Save pointers on both sides */
		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
		ccb->ccb_h.io_ptr = io;

		/*
		 * Only SCSI I/O comes down this path, resets, etc. come
		 * down via the XPT_RESET_BUS/LUN CCBs below.
		 */
		io->io_hdr.io_type = CTL_IO_SCSI;
		io->io_hdr.nexus.initid.id = 1;
		io->io_hdr.nexus.targ_port = softc->fe.targ_port;
		/*
		 * XXX KDM how do we handle target IDs?
		 */
		io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id;
		io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun;
		/*
		 * This tag scheme isn't the best, since we could in theory
		 * have a very long-lived I/O and tag collision, especially
		 * in a high I/O environment.  But it should work well
		 * enough for now.  Since we're using unsigned ints,
		 * they'll just wrap around.
		 */
		io->scsiio.tag_num = softc->cur_tag_num++;
		csio->tag_id = io->scsiio.tag_num;
		switch (csio->tag_action) {
		case CAM_TAG_ACTION_NONE:
			io->scsiio.tag_type = CTL_TAG_UNTAGGED;
			break;
		case MSG_SIMPLE_TASK:
			io->scsiio.tag_type = CTL_TAG_SIMPLE;
			break;
		case MSG_HEAD_OF_QUEUE_TASK:
        		io->scsiio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
			break;
		case MSG_ORDERED_TASK:
        		io->scsiio.tag_type = CTL_TAG_ORDERED;
			break;
		case MSG_ACA_TASK:
			io->scsiio.tag_type = CTL_TAG_ACA;
			break;
		default:
			io->scsiio.tag_type = CTL_TAG_UNTAGGED;
			printf("%s: unhandled tag type %#x!!\n", __func__,
			       csio->tag_action);
			break;
		}
		if (csio->cdb_len > sizeof(io->scsiio.cdb)) {
			printf("%s: WARNING: CDB len %d > ctl_io space %zd\n",
			       __func__, csio->cdb_len, sizeof(io->scsiio.cdb));
		}
		io->scsiio.cdb_len = min(csio->cdb_len, sizeof(io->scsiio.cdb));
		bcopy(csio->cdb_io.cdb_bytes, io->scsiio.cdb,
		      io->scsiio.cdb_len);

		err = ctl_queue(io);
		if (err != CTL_RETVAL_COMPLETE) {
			printf("%s: func %d: error %d returned by "
			       "ctl_queue()!\n", __func__,
			       ccb->ccb_h.func_code, err);
			ctl_free_io(io);
		} else {
			ccb->ccb_h.status |= CAM_SIM_QUEUED;
		}
		break;
	}
	case XPT_ABORT: {
		union ctl_io *io;
		union ccb *abort_ccb;

		abort_ccb = ccb->cab.abort_ccb;

		if (abort_ccb->ccb_h.func_code != XPT_SCSI_IO) {
			ccb->ccb_h.status = CAM_REQ_INVALID;
			xpt_done(ccb);
		}

		/*
		 * If we aren't online, there are no devices to talk to.
		 */
		if (softc->online == 0) {
			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
			xpt_done(ccb);
			return;
		}

		io = ctl_alloc_io(softc->fe.ctl_pool_ref);
		if (io == NULL) {
			ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
			xpt_freeze_devq(ccb->ccb_h.path, 1);
			xpt_done(ccb);
			return;
		}

		ctl_zero_io(io);
		/* Save pointers on both sides */
		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
		ccb->ccb_h.io_ptr = io;

		io->io_hdr.io_type = CTL_IO_TASK;
		io->io_hdr.nexus.initid.id = 1;
		io->io_hdr.nexus.targ_port = softc->fe.targ_port;
		io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id;
		io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun;
		io->taskio.task_action = CTL_TASK_ABORT_TASK;
		io->taskio.tag_num = abort_ccb->csio.tag_id;
		switch (abort_ccb->csio.tag_action) {
		case CAM_TAG_ACTION_NONE:
			io->taskio.tag_type = CTL_TAG_UNTAGGED;
			break;
		case MSG_SIMPLE_TASK:
			io->taskio.tag_type = CTL_TAG_SIMPLE;
			break;
		case MSG_HEAD_OF_QUEUE_TASK:
        		io->taskio.tag_type = CTL_TAG_HEAD_OF_QUEUE;
			break;
		case MSG_ORDERED_TASK:
        		io->taskio.tag_type = CTL_TAG_ORDERED;
			break;
		case MSG_ACA_TASK:
			io->taskio.tag_type = CTL_TAG_ACA;
			break;
		default:
			io->taskio.tag_type = CTL_TAG_UNTAGGED;
			printf("%s: unhandled tag type %#x!!\n", __func__,
			       abort_ccb->csio.tag_action);
			break;
		}
		err = ctl_queue(io);
		if (err != CTL_RETVAL_COMPLETE) {
			printf("%s func %d: error %d returned by "
			       "ctl_queue()!\n", __func__,
			       ccb->ccb_h.func_code, err);
			ctl_free_io(io);
		}
		break;
	}
	case XPT_GET_TRAN_SETTINGS: {
		struct ccb_trans_settings *cts;
		struct ccb_trans_settings_scsi *scsi;
		struct ccb_trans_settings_fc *fc;

		cts = &ccb->cts;
		scsi = &cts->proto_specific.scsi;
		fc = &cts->xport_specific.fc;

		
		cts->protocol = PROTO_SCSI;
		cts->protocol_version = SCSI_REV_SPC2;
		cts->transport = XPORT_FC;
		cts->transport_version = 0;

		scsi->valid = CTS_SCSI_VALID_TQ;
		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
		fc->valid = CTS_FC_VALID_SPEED;
		fc->bitrate = 800000;
		fc->wwnn = softc->wwnn;
		fc->wwpn = softc->wwpn;
       		fc->port = softc->fe.targ_port;
		fc->valid |= CTS_FC_VALID_WWNN | CTS_FC_VALID_WWPN |
			CTS_FC_VALID_PORT; 
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	case XPT_SET_TRAN_SETTINGS:
		/* XXX KDM should we actually do something here? */
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	case XPT_RESET_BUS:
	case XPT_RESET_DEV: {
		union ctl_io *io;

		/*
		 * If we aren't online, there are no devices to talk to.
		 */
		if (softc->online == 0) {
			ccb->ccb_h.status = CAM_DEV_NOT_THERE;
			xpt_done(ccb);
			return;
		}

		io = ctl_alloc_io(softc->fe.ctl_pool_ref);
		if (io == NULL) {
			ccb->ccb_h.status = CAM_BUSY | CAM_DEV_QFRZN;
			xpt_freeze_devq(ccb->ccb_h.path, 1);
			xpt_done(ccb);
			return;
		}

		ctl_zero_io(io);
		/* Save pointers on both sides */
		io->io_hdr.ctl_private[CTL_PRIV_FRONTEND].ptr = ccb;
		ccb->ccb_h.io_ptr = io;

		io->io_hdr.io_type = CTL_IO_TASK;
		io->io_hdr.nexus.initid.id = 0;
		io->io_hdr.nexus.targ_port = softc->fe.targ_port;
		io->io_hdr.nexus.targ_target.id = ccb->ccb_h.target_id;
		io->io_hdr.nexus.targ_lun = ccb->ccb_h.target_lun;
		if (ccb->ccb_h.func_code == XPT_RESET_BUS)
			io->taskio.task_action = CTL_TASK_BUS_RESET;
		else
			io->taskio.task_action = CTL_TASK_LUN_RESET;

		err = ctl_queue(io);
		if (err != CTL_RETVAL_COMPLETE) {
			printf("%s func %d: error %d returned by "
			      "ctl_queue()!\n", __func__,
			      ccb->ccb_h.func_code, err);
			ctl_free_io(io);
		}
		break;
	}
	case XPT_CALC_GEOMETRY:
		cam_calc_geometry(&ccb->ccg, 1);
		xpt_done(ccb);
		break;
	case XPT_PATH_INQ: {
		struct ccb_pathinq *cpi;

		cpi = &ccb->cpi;

		cpi->version_num = 0;
		cpi->hba_inquiry = PI_TAG_ABLE;
		cpi->target_sprt = 0;
		cpi->hba_misc = 0;
		cpi->hba_eng_cnt = 0;
		cpi->max_target = 1;
		cpi->max_lun = 1024;
		/* Do we really have a limit? */
		cpi->maxio = 1024 * 1024;
		cpi->async_flags = 0;
		cpi->hpath_id = 0;
		cpi->initiator_id = 0;

		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strncpy(cpi->hba_vid, "FreeBSD", HBA_IDLEN);
		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
		cpi->unit_number = 0;
		cpi->bus_id = 0;
		cpi->base_transfer_speed = 800000;
		cpi->protocol = PROTO_SCSI;
		cpi->protocol_version = SCSI_REV_SPC2;
		/*
		 * Pretend to be Fibre Channel.
		 */
		cpi->transport = XPORT_FC;
		cpi->transport_version = 0;
		cpi->xport_specific.fc.wwnn = softc->wwnn;
		cpi->xport_specific.fc.wwpn = softc->wwpn;
		cpi->xport_specific.fc.port = softc->fe.targ_port;
		cpi->xport_specific.fc.bitrate = 8 * 1000 * 1000;
		cpi->ccb_h.status = CAM_REQ_CMP;
		break;
	}
	default:
		ccb->ccb_h.status = CAM_PROVIDE_FAIL;
		printf("%s: unsupported CCB type %#x\n", __func__,
		       ccb->ccb_h.func_code);
		xpt_done(ccb);
		break;
	}
}
Esempio n. 7
0
static void
ahaexecuteccb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{
	struct	 aha_ccb *accb;
	union	 ccb *ccb;
	struct	 aha_softc *aha;
	uint32_t paddr;

	accb = (struct aha_ccb *)arg;
	ccb = accb->ccb;
	aha = (struct aha_softc *)ccb->ccb_h.ccb_aha_ptr;

	if (error != 0) {
		if (error != EFBIG)
			device_printf(aha->dev,
			    "Unexepected error 0x%x returned from "
			    "bus_dmamap_load\n", error);
		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
		}
		ahafreeccb(aha, accb);
		xpt_done(ccb);
		return;
	}

	if (nseg != 0) {
		aha_sg_t *sg;
		bus_dma_segment_t *end_seg;
		bus_dmasync_op_t op;

		end_seg = dm_segs + nseg;

		/* Copy the segments into our SG list */
		sg = accb->sg_list;
		while (dm_segs < end_seg) {
			ahautoa24(dm_segs->ds_len, sg->len);
			ahautoa24(dm_segs->ds_addr, sg->addr);
			sg++;
			dm_segs++;
		}

		if (nseg > 1) {
			accb->hccb.opcode = aha->ccb_sg_opcode;
			ahautoa24((sizeof(aha_sg_t) * nseg),
			    accb->hccb.data_len);
			ahautoa24(accb->sg_list_phys, accb->hccb.data_addr);
		} else {
			bcopy(accb->sg_list->len, accb->hccb.data_len, 3);
			bcopy(accb->sg_list->addr, accb->hccb.data_addr, 3);
		}

		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
			op = BUS_DMASYNC_PREREAD;
		else
			op = BUS_DMASYNC_PREWRITE;

		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);

	} else {
		accb->hccb.opcode = INITIATOR_CCB;
		ahautoa24(0, accb->hccb.data_len);
		ahautoa24(0, accb->hccb.data_addr);
	}

	/*
	 * Last time we need to check if this CCB needs to
	 * be aborted.
	 */
	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
		if (nseg != 0)
			bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
		ahafreeccb(aha, accb);
		xpt_done(ccb);
		return;
	}

	accb->flags = ACCB_ACTIVE;
	ccb->ccb_h.status |= CAM_SIM_QUEUED;
	LIST_INSERT_HEAD(&aha->pending_ccbs, &ccb->ccb_h, sim_links.le);

	callout_reset_sbt(&accb->timer, SBT_1MS * ccb->ccb_h.timeout, 0,
	    ahatimeout, accb, 0);

	/* Tell the adapter about this command */
	if (aha->cur_outbox->action_code != AMBO_FREE) {
		/*
		 * We should never encounter a busy mailbox.
		 * If we do, warn the user, and treat it as
		 * a resource shortage.  If the controller is
		 * hung, one of the pending transactions will
		 * timeout causing us to start recovery operations.
		 */
		device_printf(aha->dev,
		    "Encountered busy mailbox with %d out of %d "
		    "commands active!!!", aha->active_ccbs, aha->max_ccbs);
		callout_stop(&accb->timer);
		if (nseg != 0)
			bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
		ahafreeccb(aha, accb);
		aha->resource_shortage = TRUE;
		xpt_freeze_simq(aha->sim, /*count*/1);
		ccb->ccb_h.status = CAM_REQUEUE_REQ;
		xpt_done(ccb);
		return;
	}
	paddr = ahaccbvtop(aha, accb);
	ahautoa24(paddr, aha->cur_outbox->ccb_addr);
	aha->cur_outbox->action_code = AMBO_START;
	aha_outb(aha, COMMAND_REG, AOP_START_MBOX);

	ahanextoutbox(aha);
}
Esempio n. 8
0
static void
ahadone(struct aha_softc *aha, struct aha_ccb *accb, aha_mbi_comp_code_t comp_code)
{
	union  ccb	  *ccb;
	struct ccb_scsiio *csio;

	ccb = accb->ccb;
	csio = &accb->ccb->csio;

	if ((accb->flags & ACCB_ACTIVE) == 0) {
		device_printf(aha->dev, 
		    "ahadone - Attempt to free non-active ACCB %p\n",
		    (void *)accb);
		return;
	}

	if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
		bus_dmasync_op_t op;

		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN)
			op = BUS_DMASYNC_POSTREAD;
		else
			op = BUS_DMASYNC_POSTWRITE;
		bus_dmamap_sync(aha->buffer_dmat, accb->dmamap, op);
		bus_dmamap_unload(aha->buffer_dmat, accb->dmamap);
	}

	if (accb == aha->recovery_accb) {
		/*
		 * The recovery ACCB does not have a CCB associated
		 * with it, so short circuit the normal error handling.
		 * We now traverse our list of pending CCBs and process
		 * any that were terminated by the recovery CCBs action.
		 * We also reinstate timeouts for all remaining, pending,
		 * CCBs.
		 */
		struct cam_path *path;
		struct ccb_hdr *ccb_h;
		cam_status error;

		/* Notify all clients that a BDR occurred */
		error = xpt_create_path(&path, /*periph*/NULL,
		    cam_sim_path(aha->sim), accb->hccb.target,
		    CAM_LUN_WILDCARD);

		if (error == CAM_REQ_CMP) {
			xpt_async(AC_SENT_BDR, path, NULL);
			xpt_free_path(path);
		}

		ccb_h = LIST_FIRST(&aha->pending_ccbs);
		while (ccb_h != NULL) {
			struct aha_ccb *pending_accb;

			pending_accb = (struct aha_ccb *)ccb_h->ccb_accb_ptr;
			if (pending_accb->hccb.target == accb->hccb.target) {
				pending_accb->hccb.ahastat = AHASTAT_HA_BDR;
				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
				ahadone(aha, pending_accb, AMBI_ERROR);
			} else {
				callout_reset_sbt(&pending_accb->timer,
				    SBT_1MS * ccb_h->timeout, 0, ahatimeout,
				    pending_accb, 0);
				ccb_h = LIST_NEXT(ccb_h, sim_links.le);
			}
		}
		device_printf(aha->dev, "No longer in timeout\n");
		return;
	}

	callout_stop(&accb->timer);

	switch (comp_code) {
	case AMBI_FREE:
		device_printf(aha->dev,
		    "ahadone - CCB completed with free status!\n");
		break;
	case AMBI_NOT_FOUND:
		device_printf(aha->dev,
		    "ahadone - CCB Abort failed to find CCB\n");
		break;
	case AMBI_ABORT:
	case AMBI_ERROR:
		/* An error occurred */
		if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
			csio->resid = 0;
		else
			csio->resid = aha_a24tou(accb->hccb.data_len);
		switch(accb->hccb.ahastat) {
		case AHASTAT_DATARUN_ERROR:
		{
			if (csio->resid <= 0) {
				csio->ccb_h.status = CAM_DATA_RUN_ERR;
				break;
			}
			/* FALLTHROUGH */
		}
		case AHASTAT_NOERROR:
			csio->scsi_status = accb->hccb.sdstat;
			csio->ccb_h.status |= CAM_SCSI_STATUS_ERROR;
			switch(csio->scsi_status) {
			case SCSI_STATUS_CHECK_COND:
			case SCSI_STATUS_CMD_TERMINATED:
				csio->ccb_h.status |= CAM_AUTOSNS_VALID;
				/*
				 * The aha writes the sense data at different
				 * offsets based on the scsi cmd len
				 */
				bcopy((caddr_t) &accb->hccb.scsi_cdb +
				    accb->hccb.cmd_len,
				    (caddr_t) &csio->sense_data,
				    accb->hccb.sense_len);
				break;
			default:
				break;
			case SCSI_STATUS_OK:
				csio->ccb_h.status = CAM_REQ_CMP;
				break;
			}
			break;
		case AHASTAT_SELTIMEOUT:
			csio->ccb_h.status = CAM_SEL_TIMEOUT;
			break;
		case AHASTAT_UNEXPECTED_BUSFREE:
			csio->ccb_h.status = CAM_UNEXP_BUSFREE;
			break;
		case AHASTAT_INVALID_PHASE:
			csio->ccb_h.status = CAM_SEQUENCE_FAIL;
			break;
		case AHASTAT_INVALID_ACTION_CODE:
			panic("%s: Inavlid Action code", aha_name(aha));
			break;
		case AHASTAT_INVALID_OPCODE:
			if (accb->hccb.opcode < INITIATOR_CCB_WRESID)
				panic("%s: Invalid CCB Opcode %x hccb = %p",
				    aha_name(aha), accb->hccb.opcode,
				    &accb->hccb);
			device_printf(aha->dev,
			    "AHA-1540A compensation failed\n");
			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
			csio->ccb_h.status = CAM_REQUEUE_REQ;
			break;
		case AHASTAT_LINKED_CCB_LUN_MISMATCH:
			/* We don't even support linked commands... */
			panic("%s: Linked CCB Lun Mismatch", aha_name(aha));
			break;
		case AHASTAT_INVALID_CCB_OR_SG_PARAM:
			panic("%s: Invalid CCB or SG list", aha_name(aha));
			break;
		case AHASTAT_HA_SCSI_BUS_RESET:
			if ((csio->ccb_h.status & CAM_STATUS_MASK)
			    != CAM_CMD_TIMEOUT)
				csio->ccb_h.status = CAM_SCSI_BUS_RESET;
			break;
		case AHASTAT_HA_BDR:
			if ((accb->flags & ACCB_DEVICE_RESET) == 0)
				csio->ccb_h.status = CAM_BDR_SENT;
			else
				csio->ccb_h.status = CAM_CMD_TIMEOUT;
			break;
		}
		if (csio->ccb_h.status != CAM_REQ_CMP) {
			xpt_freeze_devq(csio->ccb_h.path, /*count*/1);
			csio->ccb_h.status |= CAM_DEV_QFRZN;
		}
		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
		ahafreeccb(aha, accb);
		xpt_done(ccb);
		break;
	case AMBI_OK:
		/* All completed without incident */
		/* XXX DO WE NEED TO COPY SENSE BYTES HERE???? XXX */
		/* I don't think so since it works???? */
		ccb->ccb_h.status |= CAM_REQ_CMP;
		if ((accb->flags & ACCB_RELEASE_SIMQ) != 0)
			ccb->ccb_h.status |= CAM_RELEASE_SIMQ;
		ahafreeccb(aha, accb);
		xpt_done(ccb);
		break;
	}
}
Esempio n. 9
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);
		}
	}
}
Esempio n. 10
0
/*
 * Callback routine from "bus_dmamap_load" or in simple case called directly.
 *
 * Takes a list of physical segments and builds the SGL for SCSI IO command
 * and forwards the commard to the IOC after one last check that CAM has not
 * aborted the transaction.
 */
static void
mpt_execute_req(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{
	request_t *req;
	union ccb *ccb;
	mpt_softc_t *mpt;
	MSG_SCSI_IO_REQUEST *mpt_req;
	SGE_SIMPLE32 *se;

	req = (request_t *)arg;
	ccb = req->ccb;

	mpt = ccb->ccb_h.ccb_mpt_ptr;
	req = ccb->ccb_h.ccb_req_ptr;
	mpt_req = req->req_vbuf;

	if (error == 0 && nseg > MPT_SGL_MAX) {
		error = EFBIG;
	}

	if (error != 0) {
		if (error != EFBIG)
			mpt_prt(mpt, "bus_dmamap_load returned %d", error);
		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
			xpt_freeze_devq(ccb->ccb_h.path, 1);
			ccb->ccb_h.status = CAM_DEV_QFRZN;
			if (error == EFBIG)
				ccb->ccb_h.status |= CAM_REQ_TOO_BIG;
			else
				ccb->ccb_h.status |= CAM_REQ_CMP_ERR;
		}
		ccb->ccb_h.status &= ~CAM_SIM_QUEUED;
		xpt_done(ccb);
		CAMLOCK_2_MPTLOCK(mpt);
		mpt_free_request(mpt, req);
		MPTLOCK_2_CAMLOCK(mpt);
		return;
	}
	
	if (nseg > MPT_NSGL_FIRST(mpt)) {
		int i, nleft = nseg;
		u_int32_t flags;
		bus_dmasync_op_t op;
		SGE_CHAIN32 *ce;

		mpt_req->DataLength = ccb->csio.dxfer_len;
		flags = MPI_SGE_FLAGS_SIMPLE_ELEMENT;
		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_OUT)
			flags |= MPI_SGE_FLAGS_HOST_TO_IOC;

		se = (SGE_SIMPLE32 *) &mpt_req->SGL;
		for (i = 0; i < MPT_NSGL_FIRST(mpt) - 1; i++, se++, dm_segs++) {
			u_int32_t tf;

			bzero(se, sizeof (*se));
			se->Address = dm_segs->ds_addr;
			MPI_pSGE_SET_LENGTH(se, dm_segs->ds_len);
			tf = flags;
			if (i == MPT_NSGL_FIRST(mpt) - 2) {
				tf |= MPI_SGE_FLAGS_LAST_ELEMENT;
			}
			MPI_pSGE_SET_FLAGS(se, tf);
			nleft -= 1;
		}

		/*
		 * Tell the IOC where to find the first chain element
		 */
		mpt_req->ChainOffset = ((char *)se - (char *)mpt_req) >> 2;

		/*
		 * Until we're finished with all segments...
		 */
		while (nleft) {
			int ntodo;
			/*
			 * Construct the chain element that point to the
			 * next segment.
			 */
			ce = (SGE_CHAIN32 *) se++;
			if (nleft > MPT_NSGL(mpt)) {
				ntodo = MPT_NSGL(mpt) - 1;
				ce->NextChainOffset = (MPT_RQSL(mpt) -
				    sizeof (SGE_SIMPLE32)) >> 2;
			} else {
Esempio n. 11
0
static void
ahbexecuteecb(void *arg, bus_dma_segment_t *dm_segs, int nseg, int error)
{
	struct	  ecb *ecb;
	union	  ccb *ccb;
	struct	  ahb_softc *ahb;
	u_int32_t ecb_paddr;
	int	  s;

	ecb = (struct ecb *)arg;
	ccb = ecb->ccb;
	ahb = (struct ahb_softc *)ccb->ccb_h.ccb_ahb_ptr;

	if (error != 0) {
		if (error != EFBIG)
			printf("ahb%ld: Unexepected error 0x%x returned from "
			       "bus_dmamap_load\n", ahb->unit, error);
		if (ccb->ccb_h.status == CAM_REQ_INPROG) {
			xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
			ccb->ccb_h.status = CAM_REQ_TOO_BIG|CAM_DEV_QFRZN;
		}
		ahbecbfree(ahb, ecb);
		xpt_done(ccb);
		return;
	}
		
	ecb_paddr = ahbecbvtop(ahb, ecb);

	if (nseg != 0) {
		ahb_sg_t *sg;
		bus_dma_segment_t *end_seg;
		bus_dmasync_op_t op;

		end_seg = dm_segs + nseg;

		/* Copy the segments into our SG list */
		sg = ecb->sg_list;
		while (dm_segs < end_seg) {
			sg->addr = dm_segs->ds_addr;
			sg->len = dm_segs->ds_len;
			sg++;
			dm_segs++;
		}

		if (nseg > 1) {
			ecb->hecb.flag_word1 |= FW1_SG_ECB;
			ecb->hecb.data_ptr = ahbsgpaddr(ecb_paddr);
			ecb->hecb.data_len = sizeof(ahb_sg_t) * nseg;
		} else {
			ecb->hecb.data_ptr = ecb->sg_list->addr;
			ecb->hecb.data_len = ecb->sg_list->len;
		}

		if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_IN) {
/*			ecb->hecb.flag_word2 |= FW2_DATA_DIR_IN; */
			op = BUS_DMASYNC_PREREAD;
		} else {
			op = BUS_DMASYNC_PREWRITE;
		}
		/* ecb->hecb.flag_word2 |= FW2_CHECK_DATA_DIR; */

		bus_dmamap_sync(ahb->buffer_dmat, ecb->dmamap, op);

	} else {
		ecb->hecb.data_ptr = 0;
		ecb->hecb.data_len = 0;
	}

	s = splcam();

	/*
	 * Last time we need to check if this CCB needs to
	 * be aborted.
	 */
	if (ccb->ccb_h.status != CAM_REQ_INPROG) {
		if (nseg != 0)
			bus_dmamap_unload(ahb->buffer_dmat, ecb->dmamap);
		ahbecbfree(ahb, ecb);
		xpt_done(ccb);
		splx(s);
		return;
	}
		
	ecb->state = ECB_ACTIVE;
	ccb->ccb_h.status |= CAM_SIM_QUEUED;
	LIST_INSERT_HEAD(&ahb->pending_ccbs, &ccb->ccb_h, sim_links.le);

	/* Tell the adapter about this command */
	ahbqueuembox(ahb, ecb_paddr, ATTN_STARTECB|ccb->ccb_h.target_id);

	ccb->ccb_h.timeout_ch = timeout(ahbtimeout, (caddr_t)ecb,
					(ccb->ccb_h.timeout * hz) / 1000);
	splx(s);
}
Esempio n. 12
0
static void
ahbprocesserror(struct ahb_softc *ahb, struct ecb *ecb, union ccb *ccb)
{
	struct hardware_ecb *hecb;
	struct ecb_status *status;

	hecb = &ecb->hecb;
	status = &ecb->status;
	switch (status->ha_status) {
	case HS_OK:
		ccb->csio.scsi_status = status->scsi_status;
		if (status->scsi_status != 0) {
			ccb->ccb_h.status = CAM_SCSI_STATUS_ERROR;
			if (status->sense_stored) {
				ccb->ccb_h.status |= CAM_AUTOSNS_VALID;
				ccb->csio.sense_resid =
				    ccb->csio.sense_len - status->sense_len;
				bcopy(&ecb->sense, &ccb->csio.sense_data,
				      status->sense_len);
			}
		}
		break;
	case HS_TARGET_NOT_ASSIGNED:
		ccb->ccb_h.status = CAM_PATH_INVALID;
		break;
	case HS_SEL_TIMEOUT:
		ccb->ccb_h.status = CAM_SEL_TIMEOUT;
		break;
	case HS_DATA_RUN_ERR:
		ahbcalcresid(ahb, ecb, ccb);
		break;
	case HS_UNEXPECTED_BUSFREE:
		ccb->ccb_h.status = CAM_UNEXP_BUSFREE;
		break;
	case HS_INVALID_PHASE:
		ccb->ccb_h.status = CAM_SEQUENCE_FAIL;
		break;
	case HS_REQUEST_SENSE_FAILED:
		ccb->ccb_h.status = CAM_AUTOSENSE_FAIL;
		break;
	case HS_TAG_MSG_REJECTED:
	{
		struct ccb_trans_settings neg; 
		struct ccb_trans_settings_scsi *scsi = &neg.proto_specific.scsi;

		xpt_print_path(ccb->ccb_h.path);
		printf("refuses tagged commands.  Performing "
		       "non-tagged I/O\n");
		memset(&neg, 0, sizeof (neg));
		neg.protocol = PROTO_SCSI;
		neg.protocol_version = SCSI_REV_2;
		neg.transport = XPORT_SPI;
		neg.transport_version = 2;
		scsi->flags = CTS_SCSI_VALID_TQ;
		xpt_setup_ccb(&neg.ccb_h, ccb->ccb_h.path, /*priority*/1); 
		xpt_async(AC_TRANSFER_NEG, ccb->ccb_h.path, &neg);
		ahb->tags_permitted &= ~(0x01 << ccb->ccb_h.target_id);
		ccb->ccb_h.status = CAM_MSG_REJECT_REC;
		break;
	}
	case HS_FIRMWARE_LOAD_REQ:
	case HS_HARDWARE_ERR:
		/*
		 * Tell the system that the Adapter
		 * is no longer functional.
		 */
		ccb->ccb_h.status = CAM_NO_HBA;
		break;
	case HS_CMD_ABORTED_HOST:
	case HS_CMD_ABORTED_ADAPTER:
	case HS_ATN_TARGET_FAILED:
	case HS_SCSI_RESET_ADAPTER:
	case HS_SCSI_RESET_INCOMING:
		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
		break;
	case HS_INVALID_ECB_PARAM:
		printf("ahb%ld: opcode 0x%02x, flag_word1 0x%02x, flag_word2 0x%02x\n",
			ahb->unit, hecb->opcode, hecb->flag_word1, hecb->flag_word2);	
		ccb->ccb_h.status = CAM_SCSI_BUS_RESET;
		break;
	case HS_DUP_TCB_RECEIVED:
	case HS_INVALID_OPCODE:
	case HS_INVALID_CMD_LINK:
	case HS_PROGRAM_CKSUM_ERROR:
		panic("ahb%ld: Can't happen host status %x occurred",
		      ahb->unit, status->ha_status);
		break;
	}
	if (ccb->ccb_h.status != CAM_REQ_CMP) {
		xpt_freeze_devq(ccb->ccb_h.path, /*count*/1);
		ccb->ccb_h.status |= CAM_DEV_QFRZN;
	}
}
Esempio n. 13
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);
}