Beispiel #1
0
static void
adv_action(struct cam_sim *sim, union ccb *ccb)
{
	struct adv_softc *adv;

	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("adv_action\n"));

	adv = (struct adv_softc *)cam_sim_softc(sim);

	switch (ccb->ccb_h.func_code) {
	/* Common cases first */
	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
	{
		struct	ccb_hdr *ccb_h;
		struct	ccb_scsiio *csio;
		struct	adv_ccb_info *cinfo;

		ccb_h = &ccb->ccb_h;
		csio = &ccb->csio;
		cinfo = adv_get_ccb_info(adv);
		if (cinfo == NULL)
			panic("XXX Handle CCB info error!!!");

		ccb_h->ccb_cinfo_ptr = cinfo;
		cinfo->ccb = ccb;

		/* Only use S/G if there is a transfer */
		if ((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
			if ((ccb_h->flags & CAM_SCATTER_VALID) == 0) {
				/*
				 * We've been given a pointer
				 * to a single buffer
				 */
				if ((ccb_h->flags & CAM_DATA_PHYS) == 0) {
					int s;
					int error;

					s = splsoftvm();
					error =
					    bus_dmamap_load(adv->buffer_dmat,
							    cinfo->dmamap,
							    csio->data_ptr,
							    csio->dxfer_len,
							    adv_execute_ccb,
							    csio, /*flags*/0);
					if (error == EINPROGRESS) {
						/*
						 * So as to maintain ordering,
						 * freeze the controller queue
						 * until our mapping is
						 * returned.
						 */
						adv_set_state(adv,
							      ADV_BUSDMA_BLOCK);
					}
					splx(s);
				} else {
					struct bus_dma_segment seg;

					/* Pointer to physical buffer */
					seg.ds_addr =
					     (bus_addr_t)csio->data_ptr;
					seg.ds_len = csio->dxfer_len;
					adv_execute_ccb(csio, &seg, 1, 0);
				}
			} else {
				struct bus_dma_segment *segs;
				if ((ccb_h->flags & CAM_DATA_PHYS) != 0)
					panic("adv_setup_data - Physical "
					      "segment pointers unsupported");

				if ((ccb_h->flags & CAM_SG_LIST_PHYS) == 0)
					panic("adv_setup_data - Virtual "
					      "segment addresses unsupported");

				/* Just use the segments provided */
				segs = (struct bus_dma_segment *)csio->data_ptr;
				adv_execute_ccb(ccb, segs, csio->sglist_cnt, 0);
			}
		} else {
			adv_execute_ccb(ccb, NULL, 0, 0);
		}
		break;
	}
	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
	case XPT_TARGET_IO:	/* Execute target I/O request */
	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
	case XPT_EN_LUN:		/* Enable LUN as a target */
	case XPT_ABORT:			/* Abort the specified CCB */
		/* XXX Implement */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
#define	IS_CURRENT_SETTINGS(c)	(c->type == CTS_TYPE_CURRENT_SETTINGS)
#define	IS_USER_SETTINGS(c)	(c->type == CTS_TYPE_USER_SETTINGS)
	case XPT_SET_TRAN_SETTINGS:
	{
		struct ccb_trans_settings_scsi *scsi;
		struct ccb_trans_settings_spi *spi;
		struct	 ccb_trans_settings *cts;
		target_bit_vector targ_mask;
		struct adv_transinfo *tconf;
		u_int	 update_type;
		int	 s;

		cts = &ccb->cts;
		targ_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);
		update_type = 0;

		/*
		 * The user must specify which type of settings he wishes
		 * to change.
		 */
		if (IS_CURRENT_SETTINGS(cts) && !IS_USER_SETTINGS(cts)) {
			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
			update_type |= ADV_TRANS_GOAL;
		} else if (IS_USER_SETTINGS(cts) && !IS_CURRENT_SETTINGS(cts)) {
			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
			update_type |= ADV_TRANS_USER;
		} else {
			ccb->ccb_h.status = CAM_REQ_INVALID;
			break;
		}
		
		s = splcam();
		scsi = &cts->proto_specific.scsi;
		spi = &cts->xport_specific.spi;
		if ((update_type & ADV_TRANS_GOAL) != 0) {
			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
				if ((spi->flags & CTS_SPI_FLAGS_DISC_ENB) != 0)
					adv->disc_enable |= targ_mask;
				else
					adv->disc_enable &= ~targ_mask;
				adv_write_lram_8(adv, ADVV_DISC_ENABLE_B,
						 adv->disc_enable); 
			}

			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
					adv->cmd_qng_enabled |= targ_mask;
				else
					adv->cmd_qng_enabled &= ~targ_mask;
			}
		}

		if ((update_type & ADV_TRANS_USER) != 0) {
			if ((spi->valid & CTS_SPI_VALID_DISC) != 0) {
				if ((spi->flags & CTS_SPI_VALID_DISC) != 0)
					adv->user_disc_enable |= targ_mask;
				else
					adv->user_disc_enable &= ~targ_mask;
			}

			if ((scsi->valid & CTS_SCSI_VALID_TQ) != 0) {
				if ((scsi->flags & CTS_SCSI_FLAGS_TAG_ENB) != 0)
					adv->user_cmd_qng_enabled |= targ_mask;
				else
					adv->user_cmd_qng_enabled &= ~targ_mask;
			}
		}
		
		/*
		 * If the user specifies either the sync rate, or offset,
		 * but not both, the unspecified parameter defaults to its
		 * current value in transfer negotiations.
		 */
		if (((spi->valid & CTS_SPI_VALID_SYNC_RATE) != 0)
		 || ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) != 0)) {
			/*
			 * If the user provided a sync rate but no offset,
			 * use the current offset.
			 */
			if ((spi->valid & CTS_SPI_VALID_SYNC_OFFSET) == 0)
				spi->sync_offset = tconf->offset;

			/*
			 * If the user provided an offset but no sync rate,
			 * use the current sync rate.
			 */
			if ((spi->valid & CTS_SPI_VALID_SYNC_RATE) == 0)
				spi->sync_period = tconf->period;

			adv_period_offset_to_sdtr(adv, &spi->sync_period,
						  &spi->sync_offset,
						  cts->ccb_h.target_id);
			
			adv_set_syncrate(adv, /*struct cam_path */NULL,
					 cts->ccb_h.target_id, spi->sync_period,
					 spi->sync_offset, update_type);
		}

		splx(s);
		ccb->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}
	case XPT_GET_TRAN_SETTINGS:
	/* Get default/user set transfer settings for the target */
	{
		struct ccb_trans_settings_scsi *scsi;
		struct ccb_trans_settings_spi *spi;
		struct ccb_trans_settings *cts;
		struct adv_transinfo *tconf;
		target_bit_vector target_mask;
		int s;

		cts = &ccb->cts;
		target_mask = ADV_TID_TO_TARGET_MASK(cts->ccb_h.target_id);

		scsi = &cts->proto_specific.scsi;
		spi = &cts->xport_specific.spi;

		cts->protocol = PROTO_SCSI;
		cts->protocol_version = SCSI_REV_2;
		cts->transport = XPORT_SPI;
		cts->transport_version = 2;

		scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
		spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;

		s = splcam();
		if (cts->type == CTS_TYPE_CURRENT_SETTINGS) {
			tconf = &adv->tinfo[cts->ccb_h.target_id].current;
			if ((adv->disc_enable & target_mask) != 0)
				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
			if ((adv->cmd_qng_enabled & target_mask) != 0)
				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
		} else {
			tconf = &adv->tinfo[cts->ccb_h.target_id].user;
			if ((adv->user_disc_enable & target_mask) != 0)
				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
			if ((adv->user_cmd_qng_enabled & target_mask) != 0)
				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
		}
		spi->sync_period = tconf->period;
		spi->sync_offset = tconf->offset;
		splx(s);
		spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
		spi->valid = CTS_SPI_VALID_SYNC_RATE
			   | CTS_SPI_VALID_SYNC_OFFSET
			   | CTS_SPI_VALID_BUS_WIDTH
			   | CTS_SPI_VALID_DISC;
		scsi->valid = CTS_SCSI_VALID_TQ;
		ccb->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}
	case XPT_CALC_GEOMETRY:
	{
		int	  extended;

		extended = (adv->control & ADV_CNTL_BIOS_GT_1GB) != 0;
		cam_calc_geometry(&ccb->ccg, extended); 
		xpt_done(ccb);
		break;
	}
	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
	{
		int s;

		s = splcam();
		adv_stop_execution(adv);
		adv_reset_bus(adv, /*initiate_reset*/TRUE);
		adv_start_execution(adv);
		splx(s);

		ccb->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}
	case XPT_TERM_IO:		/* Terminate the I/O process */
		/* XXX Implement */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	case XPT_PATH_INQ:		/* Path routing inquiry */
	{
		struct ccb_pathinq *cpi = &ccb->cpi;
		
		cpi->version_num = 1; /* XXX??? */
		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
		cpi->target_sprt = 0;
		cpi->hba_misc = 0;
		cpi->hba_eng_cnt = 0;
		cpi->max_target = 7;
		cpi->max_lun = 7;
		cpi->initiator_id = adv->scsi_id;
		cpi->bus_id = cam_sim_bus(sim);
		cpi->base_transfer_speed = 3300;
		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strncpy(cpi->hba_vid, "Advansys", HBA_IDLEN);
		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
		cpi->unit_number = cam_sim_unit(sim);
		cpi->ccb_h.status = CAM_REQ_CMP;
                cpi->transport = XPORT_SPI;
                cpi->transport_version = 2;
                cpi->protocol = PROTO_SCSI;
                cpi->protocol_version = SCSI_REV_2;
		xpt_done(ccb);
		break;
	}
	default:
		ccb->ccb_h.status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	}
}
/**
 * mrsas_action:            SIM callback entry point   
 * input:                   pointer to SIM 
 *                          pointer to CAM Control Block
 *
 * This function processes CAM subsystem requests. The type of request is
 * stored in ccb->ccb_h.func_code.  The preprocessor #ifdef is necessary
 * because ccb->cpi.maxio is not supported for FreeBSD version 7.4 or 
 * earlier.   
 */
static void mrsas_action(struct cam_sim *sim, union ccb *ccb)
{
    struct mrsas_softc *sc = (struct mrsas_softc *)cam_sim_softc(sim);
    struct ccb_hdr *ccb_h = &(ccb->ccb_h);
    u_int32_t device_id;

    switch (ccb->ccb_h.func_code) {
        case XPT_SCSI_IO:
        {
            device_id = ccb_h->target_id;

            /* 
             * bus 0 is LD, bus 1 is for system-PD 
             */ 
            if (cam_sim_bus(sim) == 1 && 
                sc->pd_list[device_id].driveState != MR_PD_STATE_SYSTEM) {
                ccb->ccb_h.status |= CAM_DEV_NOT_THERE;
                xpt_done(ccb);
            }
            else {
                if (mrsas_startio(sc, sim, ccb)){
                    ccb->ccb_h.status |= CAM_REQ_INVALID;
                    xpt_done(ccb);
                }
            }
            break;
        }
        case XPT_ABORT:
        {
            ccb->ccb_h.status = CAM_UA_ABORT;
            xpt_done(ccb);
            break;
        }
        case XPT_RESET_BUS:
        {
            xpt_done(ccb);
            break;
        }
        case XPT_GET_TRAN_SETTINGS:
        {
            ccb->cts.protocol = PROTO_SCSI;
            ccb->cts.protocol_version = SCSI_REV_2;
            ccb->cts.transport = XPORT_SPI;
            ccb->cts.transport_version = 2;  
            ccb->cts.xport_specific.spi.valid = CTS_SPI_VALID_DISC;
            ccb->cts.xport_specific.spi.flags = CTS_SPI_FLAGS_DISC_ENB;
            ccb->cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
            ccb->cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
            ccb->ccb_h.status = CAM_REQ_CMP;
            xpt_done(ccb);
            break;
        }
        case XPT_SET_TRAN_SETTINGS:
        {
            ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; 
            xpt_done(ccb);
            break;
        }
        case XPT_CALC_GEOMETRY:
        {
            cam_calc_geometry(&ccb->ccg, 1);   
            xpt_done(ccb);
            break;
        }
        case XPT_PATH_INQ:
        {
            ccb->cpi.version_num = 1;
            ccb->cpi.hba_inquiry = 0;
            ccb->cpi.target_sprt = 0;
            ccb->cpi.hba_misc = 0;
            ccb->cpi.hba_eng_cnt = 0;
            ccb->cpi.max_lun = MRSAS_SCSI_MAX_LUNS;
            ccb->cpi.unit_number = cam_sim_unit(sim);
            ccb->cpi.bus_id = cam_sim_bus(sim);
            ccb->cpi.initiator_id = MRSAS_SCSI_INITIATOR_ID; 
            ccb->cpi.base_transfer_speed = 150000; 
            strncpy(ccb->cpi.sim_vid, "FreeBSD", SIM_IDLEN);
            strncpy(ccb->cpi.hba_vid, "LSI", HBA_IDLEN);
            strncpy(ccb->cpi.dev_name, cam_sim_name(sim), DEV_IDLEN);
            ccb->cpi.transport = XPORT_SPI;
            ccb->cpi.transport_version = 2;
            ccb->cpi.protocol = PROTO_SCSI;
            ccb->cpi.protocol_version = SCSI_REV_2;
            if (ccb->cpi.bus_id == 0)
                ccb->cpi.max_target = MRSAS_MAX_LD-1;
            else
                ccb->cpi.max_target = MRSAS_MAX_PD-1;
            ccb->cpi.maxio = MRSAS_MAX_IO_SIZE;
            ccb->ccb_h.status = CAM_REQ_CMP;
            xpt_done(ccb);
            break;
        }
        default:
        {
            ccb->ccb_h.status = CAM_REQ_INVALID;
            xpt_done(ccb);
            break;
        }
    }
}
Beispiel #3
0
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
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;
	}
}
Beispiel #5
0
/*
 * Action function - dispatch command
 */
static
void
ahci_xpt_action(struct cam_sim *sim, union ccb *ccb)
{
	struct ahci_port *ap;
	struct ata_port	 *at, *atx;
	struct ccb_hdr *ccbh;
	int unit;

	/* XXX lock */
	ap = cam_sim_softc(sim);
	atx = NULL;
	KKASSERT(ap != NULL);
	ccbh = &ccb->ccb_h;
	unit = cam_sim_unit(sim);

	/*
	 * Early failure checks.  These checks do not apply to XPT_PATH_INQ,
	 * otherwise the bus rescan will not remove the dead devices when
	 * unplugging a PM.
	 *
	 * For non-wildcards we have one target (0) and one lun (0),
	 * unless we have a port multiplier.
	 *
	 * A wildcard target indicates only the general bus is being
	 * probed.
	 *
	 * Calculate at and atx.  at is always non-NULL.  atx is only
	 * NULL for direct-attached devices.  It will be non-NULL for
	 * devices behind a port multiplier.
	 *
	 * XXX What do we do with a LUN wildcard?
	 */
	if (ccbh->target_id != CAM_TARGET_WILDCARD &&
	    ccbh->func_code != XPT_PATH_INQ) {
		if (ap->ap_type == ATA_PORT_T_NONE) {
			ccbh->status = CAM_DEV_NOT_THERE;
			xpt_done(ccb);
			return;
		}
		if (ccbh->target_id < 0 || ccbh->target_id >= ap->ap_pmcount) {
			ccbh->status = CAM_DEV_NOT_THERE;
			xpt_done(ccb);
			return;
		}
		at = ap->ap_ata[ccbh->target_id];
		if (ap->ap_type == ATA_PORT_T_PM)
			atx = at;

		if (ccbh->target_lun != CAM_LUN_WILDCARD && ccbh->target_lun) {
			ccbh->status = CAM_DEV_NOT_THERE;
			xpt_done(ccb);
			return;
		}
	} else {
		at = ap->ap_ata[0];
	}

	/*
	 * Switch on the meta XPT command
	 */
	switch(ccbh->func_code) {
	case XPT_ENG_EXEC:
		/*
		 * This routine is called after a port multiplier has been
		 * probed.
		 */
		ccbh->status = CAM_REQ_CMP;
		ahci_os_lock_port(ap);
		ahci_port_state_machine(ap, 0);
		ahci_os_unlock_port(ap);
		xpt_done(ccb);
		ahci_xpt_rescan(ap);
		break;
	case XPT_PATH_INQ:
		/*
		 * This command always succeeds, otherwise the bus scan
		 * will not detach dead devices.
		 */
		ccb->cpi.version_num = 1;
		ccb->cpi.hba_inquiry = 0;
		ccb->cpi.target_sprt = 0;
		ccb->cpi.hba_misc = PIM_SEQSCAN;
		ccb->cpi.hba_eng_cnt = 0;
		bzero(ccb->cpi.vuhba_flags, sizeof(ccb->cpi.vuhba_flags));
		ccb->cpi.max_target = AHCI_MAX_PMPORTS - 1;
		ccb->cpi.max_lun = 0;
		ccb->cpi.async_flags = 0;
		ccb->cpi.hpath_id = 0;
		ccb->cpi.initiator_id = AHCI_MAX_PMPORTS - 1;
		ccb->cpi.unit_number = cam_sim_unit(sim);
		ccb->cpi.bus_id = cam_sim_bus(sim);
		ccb->cpi.base_transfer_speed = 150000;
		ccb->cpi.transport = XPORT_SATA;
		ccb->cpi.transport_version = 1;
		ccb->cpi.protocol = PROTO_SCSI;
		ccb->cpi.protocol_version = SCSI_REV_2;

		ccbh->status = CAM_REQ_CMP;
		if (ccbh->target_id == CAM_TARGET_WILDCARD) {
			ahci_os_lock_port(ap);
			ahci_port_state_machine(ap, 0);
			ahci_os_unlock_port(ap);
		} else {
			switch(ahci_pread(ap, AHCI_PREG_SSTS) &
			       AHCI_PREG_SSTS_SPD) {
			case AHCI_PREG_SSTS_SPD_GEN1:
				ccb->cpi.base_transfer_speed = 150000;
				break;
			case AHCI_PREG_SSTS_SPD_GEN2:
				ccb->cpi.base_transfer_speed = 300000;
				break;
			case AHCI_PREG_SSTS_SPD_GEN3:
				ccb->cpi.base_transfer_speed = 600000;
				break;
			default:
				/* unknown */
				ccb->cpi.base_transfer_speed = 1000;
				break;
			}
#if 0
			if (ap->ap_type == ATA_PORT_T_NONE)
				ccbh->status = CAM_DEV_NOT_THERE;
#endif
		}
		xpt_done(ccb);
		break;
	case XPT_RESET_DEV:
		ahci_os_lock_port(ap);
		if (ap->ap_type == ATA_PORT_T_NONE) {
			ccbh->status = CAM_DEV_NOT_THERE;
		} else {
			ahci_port_reset(ap, atx, 0);
			ccbh->status = CAM_REQ_CMP;
		}
		ahci_os_unlock_port(ap);
		xpt_done(ccb);
		break;
	case XPT_RESET_BUS:
		ahci_os_lock_port(ap);
		ahci_port_reset(ap, NULL, 1);
		ahci_os_unlock_port(ap);
		ccbh->status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	case XPT_SET_TRAN_SETTINGS:
		ccbh->status = CAM_FUNC_NOTAVAIL;
		xpt_done(ccb);
		break;
	case XPT_GET_TRAN_SETTINGS:
		ccb->cts.protocol = PROTO_SCSI;
		ccb->cts.protocol_version = SCSI_REV_2;
		ccb->cts.transport = XPORT_SATA;
		ccb->cts.transport_version = XPORT_VERSION_UNSPECIFIED;
		ccb->cts.proto_specific.valid = 0;
		ccb->cts.xport_specific.valid = 0;
		ccbh->status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	case XPT_CALC_GEOMETRY:
		cam_calc_geometry(&ccb->ccg, 1);
		xpt_done(ccb);
		break;
	case XPT_SCSI_IO:
		/*
		 * Our parallel startup code might have only probed through
		 * to the IDENT, so do the last step if necessary.
		 */
		if (at->at_probe == ATA_PROBE_NEED_IDENT)
			ahci_cam_probe(ap, atx);
		if (at->at_probe != ATA_PROBE_GOOD) {
			ccbh->status = CAM_DEV_NOT_THERE;
			xpt_done(ccb);
			break;
		}
		switch(at->at_type) {
		case ATA_PORT_T_DISK:
			ahci_xpt_scsi_disk_io(ap, atx, ccb);
			break;
		case ATA_PORT_T_ATAPI:
			ahci_xpt_scsi_atapi_io(ap, atx, ccb);
			break;
		default:
			ccbh->status = CAM_REQ_INVALID;
			xpt_done(ccb);
			break;
		}
		break;
	case XPT_TRIM:
	{
		scsi_cdb_t cdb;
		struct ccb_scsiio *csio;
		csio = &ccb->csio;
		cdb = (void *)((ccbh->flags & CAM_CDB_POINTER) ?
		    csio->cdb_io.cdb_ptr : csio->cdb_io.cdb_bytes);
		cdb->generic.opcode = TRIM;
		ahci_xpt_scsi_disk_io(ap, atx, ccb);
		break;
	}
	default:
		ccbh->status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	}
}
Beispiel #6
0
/*
 * Function name:	twa_action
 * Description:		Driver entry point for CAM's use.
 *
 * Input:		sim	-- sim corresponding to the ctlr
 *			ccb	-- ptr to CAM request
 * Output:		None
 * Return value:	None
 */
TW_VOID
twa_action(struct cam_sim *sim, union ccb *ccb)
{
	struct twa_softc	*sc = (struct twa_softc *)cam_sim_softc(sim);
	struct ccb_hdr		*ccb_h = &(ccb->ccb_h);

	switch (ccb_h->func_code) {
	case XPT_SCSI_IO:	/* SCSI I/O */
	{
		struct tw_osli_req_context	*req;

		req = tw_osli_get_request(sc);
		if (req == NULL) {
			tw_osli_dbg_dprintf(2, sc, "Cannot get request pkt.");
			/*
			 * Freeze the simq to maintain ccb ordering.  The next
			 * ccb that gets completed will unfreeze the simq.
			 */
			ccb_h->status &= ~CAM_SIM_QUEUED;
			ccb_h->status |= CAM_REQUEUE_REQ;
			xpt_done(ccb);
			break;
		}

		if ((tw_cl_is_reset_needed(&(req->ctlr->ctlr_handle)))) {
			ccb_h->status &= ~CAM_SIM_QUEUED;
			ccb_h->status |= CAM_REQUEUE_REQ;
			xpt_done(ccb);
			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
			break;
		}

		req->req_handle.osl_req_ctxt = req;
		req->req_handle.is_io = TW_CL_TRUE;
		req->orig_req = ccb;
		if (tw_osli_execute_scsi(req, ccb))
			tw_osli_req_q_insert_tail(req, TW_OSLI_FREE_Q);
		break;
	}

	case XPT_ABORT:
		tw_osli_dbg_dprintf(2, sc, "Abort request.");
		ccb_h->status = CAM_UA_ABORT;
		xpt_done(ccb);
		break;

	case XPT_RESET_BUS:
		tw_cl_create_event(&(sc->ctlr_handle), TW_CL_FALSE,
			TW_CL_MESSAGE_SOURCE_FREEBSD_DRIVER,
			0x2108, 0x3, TW_CL_SEVERITY_INFO_STRING,
			"Received Reset Bus request from CAM",
			" ");

		tw_cl_set_reset_needed(&(sc->ctlr_handle));
		ccb_h->status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;

	case XPT_SET_TRAN_SETTINGS:
		tw_osli_dbg_dprintf(3, sc, "XPT_SET_TRAN_SETTINGS");

		/*
		 * This command is not supported, since it's very specific
		 * to SCSI, and we are doing ATA.
		 */
  		ccb_h->status = CAM_FUNC_NOTAVAIL;
  		xpt_done(ccb);
  		break;

	case XPT_GET_TRAN_SETTINGS: 
	{
		struct ccb_trans_settings	*cts = &ccb->cts;
		struct ccb_trans_settings_scsi *scsi =
		    &cts->proto_specific.scsi;
		struct ccb_trans_settings_spi *spi =
		    &cts->xport_specific.spi;

		cts->protocol = PROTO_SCSI;
		cts->protocol_version = SCSI_REV_2;
		cts->transport = XPORT_SPI;
		cts->transport_version = 2;

		spi->valid = CTS_SPI_VALID_DISC;
		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
		scsi->valid = CTS_SCSI_VALID_TQ;
		scsi->flags = CTS_SCSI_FLAGS_TAG_ENB;
		tw_osli_dbg_dprintf(3, sc, "XPT_GET_TRAN_SETTINGS");
		ccb_h->status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}

	case XPT_CALC_GEOMETRY:
		tw_osli_dbg_dprintf(3, sc, "XPT_CALC_GEOMETRY");
		cam_calc_geometry(&ccb->ccg, 1/* extended */);
		xpt_done(ccb);
		break;

	case XPT_PATH_INQ:    /* Path inquiry -- get twa properties */
	{
		struct ccb_pathinq	*path_inq = &ccb->cpi;

		tw_osli_dbg_dprintf(3, sc, "XPT_PATH_INQ request");

		path_inq->version_num = 1;
		path_inq->hba_inquiry = 0;
		path_inq->target_sprt = 0;
		path_inq->hba_misc = 0;
		path_inq->hba_eng_cnt = 0;
		path_inq->max_target = TW_CL_MAX_NUM_UNITS;
		path_inq->max_lun = TW_CL_MAX_NUM_LUNS - 1;
		path_inq->unit_number = cam_sim_unit(sim);
		path_inq->bus_id = cam_sim_bus(sim);
		path_inq->initiator_id = TW_CL_MAX_NUM_UNITS;
		path_inq->base_transfer_speed = 100000;
		strlcpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
		strlcpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
		strlcpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
		path_inq->transport = XPORT_SPI;
		path_inq->transport_version = 2;
		path_inq->protocol = PROTO_SCSI;
		path_inq->protocol_version = SCSI_REV_2;
		path_inq->maxio = TW_CL_MAX_IO_SIZE;
		ccb_h->status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}

	default:
		tw_osli_dbg_dprintf(3, sc, "func_code = %x", ccb_h->func_code);
		ccb_h->status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	}
}
Beispiel #7
0
static void hpt_action(struct cam_sim *sim, union ccb *ccb)
{
	PVBUS_EXT vbus_ext = (PVBUS_EXT)cam_sim_softc(sim);

	KdPrint(("hpt_action(fn=%d, id=%d)", ccb->ccb_h.func_code, ccb->ccb_h.target_id));

	hpt_assert_vbus_locked(vbus_ext);
	switch (ccb->ccb_h.func_code) {
	
	case XPT_SCSI_IO:
		hpt_scsi_io(vbus_ext, ccb);
		return;

	case XPT_RESET_BUS:
		ldm_reset_vbus((PVBUS)vbus_ext->vbus);
		break;

	case XPT_GET_TRAN_SETTINGS:
	case XPT_SET_TRAN_SETTINGS:
		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
		break;

	case XPT_CALC_GEOMETRY:
		cam_calc_geometry(&ccb->ccg, 1);
		break;

	case XPT_PATH_INQ:
	{
		struct ccb_pathinq *cpi = &ccb->cpi;

		cpi->version_num = 1;
		cpi->hba_inquiry = PI_SDTR_ABLE;
		cpi->target_sprt = 0;
		cpi->hba_misc = PIM_NOBUSRESET;
		cpi->hba_eng_cnt = 0;
		cpi->max_target = osm_max_targets;
		cpi->max_lun = 0;
		cpi->unit_number = cam_sim_unit(sim);
		cpi->bus_id = cam_sim_bus(sim);
		cpi->initiator_id = osm_max_targets;
		cpi->base_transfer_speed = 3300;

		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strncpy(cpi->hba_vid, "HPT   ", HBA_IDLEN);
		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
		cpi->transport = XPORT_SPI;
		cpi->transport_version = 2;
		cpi->protocol = PROTO_SCSI;
		cpi->protocol_version = SCSI_REV_2;
		cpi->ccb_h.status = CAM_REQ_CMP;
		break;
	}

	default:
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	}

	xpt_done(ccb);
	return;
}
Beispiel #8
0
/***********************************************************************
 * Handle a request for action from CAM
 */
static void
amr_cam_action(struct cam_sim *sim, union ccb *ccb)
{
	struct amr_softc	*sc = cam_sim_softc(sim);

	switch(ccb->ccb_h.func_code) {

	/*
	 * Perform SCSI I/O to a physical device.
	 */
	case XPT_SCSI_IO:
	{
		struct ccb_hdr		*ccbh = &ccb->ccb_h;
		struct ccb_scsiio	*csio = &ccb->csio;

		/* Validate the CCB */
		ccbh->status = CAM_REQ_INPROG;

		/* check the CDB length */
		if (csio->cdb_len > AMR_MAX_EXTCDB_LEN)
			ccbh->status = CAM_REQ_INVALID;

		if ((csio->cdb_len > AMR_MAX_CDB_LEN) &&
		    (sc->support_ext_cdb == 0))
			ccbh->status = CAM_REQ_INVALID;
	
		/* check that the CDB pointer is not to a physical address */
		if ((ccbh->flags & CAM_CDB_POINTER) &&
		    (ccbh->flags & CAM_CDB_PHYS))
			ccbh->status = CAM_REQ_INVALID;
		/*
		 * if there is data transfer, it must be to/from a virtual
		 * address
		 */
		if ((ccbh->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
			if (ccbh->flags & CAM_DATA_PHYS)
				/* we can't map it */
				ccbh->status = CAM_REQ_INVALID;
			if (ccbh->flags & CAM_SCATTER_VALID)
				/* we want to do the s/g setup */
				ccbh->status = CAM_REQ_INVALID;
		}
	
		/*
		 * If the command is to a LUN other than 0, fail it.
		 * This is probably incorrect, but during testing the
		 * firmware did not seem to respect the LUN field, and thus
		 * devices appear echoed.
		 */
		if (csio->ccb_h.target_lun != 0)
			ccbh->status = CAM_DEV_NOT_THERE;

		/* if we're happy with the request, queue it for attention */
		if (ccbh->status == CAM_REQ_INPROG) {

			/* save the channel number in the ccb */
			csio->ccb_h.sim_priv.entries[0].field= cam_sim_bus(sim);

			amr_enqueue_ccb(sc, ccb);
			amr_startio(sc);
			return;
		}
		break;
	}

	case XPT_CALC_GEOMETRY:
	{
		cam_calc_geometry(&ccb->ccg, /*extended*/1);
		break;
	}

	/*
	 * Return path stats.  Some of these should probably be amended.
	 */
	case XPT_PATH_INQ:
	{
		struct ccb_pathinq	  *cpi = & ccb->cpi;

		debug(3, "XPT_PATH_INQ");
		cpi->version_num = 1;		   /* XXX??? */
		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE|PI_WIDE_16;
		cpi->target_sprt = 0;
		cpi->hba_misc = PIM_NOBUSRESET|PIM_SEQSCAN;
		cpi->hba_eng_cnt = 0;
		cpi->max_target = AMR_MAX_TARGETS;
		cpi->max_lun = 0 /* AMR_MAX_LUNS*/;
		cpi->initiator_id = 7;		  /* XXX variable? */
		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strncpy(cpi->hba_vid, "LSI", HBA_IDLEN);
		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
		cpi->unit_number = cam_sim_unit(sim);
		cpi->bus_id = cam_sim_bus(sim);
		cpi->base_transfer_speed = 132 * 1024;  /* XXX */
		cpi->transport = XPORT_SPI;
		cpi->transport_version = 2;
		cpi->protocol = PROTO_SCSI;
		cpi->protocol_version = SCSI_REV_2;
		cpi->ccb_h.status = CAM_REQ_CMP;

		break;
	}

	case XPT_RESET_BUS:
	{
		struct ccb_pathinq	*cpi = & ccb->cpi;

		debug(1, "XPT_RESET_BUS");
		cpi->ccb_h.status = CAM_REQ_CMP;
		break;
	}

	case XPT_RESET_DEV:
	{
		debug(1, "XPT_RESET_DEV");
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	}

	case XPT_GET_TRAN_SETTINGS:
	{
		struct ccb_trans_settings	*cts = &(ccb->cts);

		debug(3, "XPT_GET_TRAN_SETTINGS");

		struct ccb_trans_settings_scsi *scsi;
		struct ccb_trans_settings_spi *spi;

		scsi = &cts->proto_specific.scsi;
		spi = &cts->xport_specific.spi;

		cts->protocol = PROTO_SCSI;
		cts->protocol_version = SCSI_REV_2;
		cts->transport = XPORT_SPI;
		cts->transport_version = 2;

		if (cts->type == CTS_TYPE_USER_SETTINGS) {
			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
			break;
		}

		spi->flags = CTS_SPI_FLAGS_DISC_ENB;
		spi->bus_width = MSG_EXT_WDTR_BUS_32_BIT;
		spi->sync_period = 6;   /* 40MHz how wide is this bus? */
		spi->sync_offset = 31;  /* How to extract this from board? */

		spi->valid = CTS_SPI_VALID_SYNC_RATE
			| CTS_SPI_VALID_SYNC_OFFSET
			| CTS_SPI_VALID_BUS_WIDTH
			| CTS_SPI_VALID_DISC;
		scsi->valid = CTS_SCSI_VALID_TQ;
		ccb->ccb_h.status = CAM_REQ_CMP;
		break;
	}

	case XPT_SET_TRAN_SETTINGS:
		debug(3, "XPT_SET_TRAN_SETTINGS");
		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
		break;


	/*
	 * Reject anything else as unsupported.
	 */
	default:
		/* we can't do this */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		break;
	}

	mtx_assert(&sc->amr_list_lock, MA_OWNED);
	xpt_done(ccb);
}
Beispiel #9
0
static void
ic_action(struct cam_sim *sim, union ccb *ccb)
{
     isc_session_t	*sp = cam_sim_softc(sim);
     struct ccb_hdr	*ccb_h = &ccb->ccb_h;

     debug_called(8);

     ccb_h->spriv_ptr0 = sp;
     sdebug(4, "func_code=0x%x flags=0x%x status=0x%x target=%d lun=%d retry_count=%d timeout=%d",
	   ccb_h->func_code, ccb->ccb_h.flags, ccb->ccb_h.status,
	   ccb->ccb_h.target_id, ccb->ccb_h.target_lun, 
	   ccb->ccb_h.retry_count, ccb_h->timeout);
     if(sp == NULL) {
	  xdebug("sp == NULL! cannot happen");
	  return;
     }	  
     switch(ccb_h->func_code) {
     case XPT_PATH_INQ:
	  _inq(sim, ccb);
	  break;

     case XPT_RESET_BUS: // (can just be a stub that does nothing and completes)
     {
	  struct ccb_pathinq *cpi = &ccb->cpi;

	  debug(3, "XPT_RESET_BUS");
	  cpi->ccb_h.status = CAM_REQ_CMP;
	  break;
     }

     case XPT_SCSI_IO: 
     {
	  struct ccb_scsiio* csio = &ccb->csio;

	  debug(4, "XPT_SCSI_IO cmd=0x%x", csio->cdb_io.cdb_bytes[0]);
	  if(sp == NULL) {
	       ccb_h->status = CAM_REQ_INVALID; //CAM_NO_NEXUS;
	       debug(4, "xpt_done.status=%d", ccb_h->status);
	       break;
	  }
	  if(ccb_h->target_lun == CAM_LUN_WILDCARD) {
	       debug(3, "target=%d: bad lun (-1)", ccb_h->target_id);
	       ccb_h->status = CAM_LUN_INVALID;
	       break;
	  }
	  if(_scsi_encap(sim, ccb) != 0)
	       return;
	  break;
     }
 
     case XPT_CALC_GEOMETRY:
     {
	  struct	ccb_calc_geometry *ccg;

	  ccg = &ccb->ccg;
	  debug(4, "sid=%d target=%d lun=%d XPT_CALC_GEOMETRY vsize=%jd bsize=%d",
		sp->sid, ccb->ccb_h.target_id, ccb->ccb_h.target_lun,
		ccg->volume_size, ccg->block_size);
	  if(ccg->block_size == 0 ||
	     (ccg->volume_size < ccg->block_size)) {
	       // print error message  ...
	       /* XXX: what error is appropiate? */
	       break;
	  } 
	  else {
	       int	lun, *off, boff;

	       lun = ccb->ccb_h.target_lun;
	       if(lun > ISCSI_MAX_LUNS) {
		    // XXX: 
		    xdebug("lun %d > ISCSI_MAX_LUNS!\n", lun);
		    lun %= ISCSI_MAX_LUNS;
	       }
	       off = &sp->target_lun[lun / (sizeof(int)*8)];
	       boff = BIT(lun % (sizeof(int)*8));
	       debug(4, "sp->target_nluns=%d *off=%x boff=%x",
		     sp->target_nluns, *off, boff);

	       if((*off & boff) == 0) {
		    sp->target_nluns++;
		    *off |= boff;
	       }
	       cam_calc_geometry(ccg, /*extended*/1);
	  }
	  break;
     }

     case XPT_GET_TRAN_SETTINGS:
     default:
	  ccb_h->status = CAM_REQ_INVALID;
	  break;
     }
#if __FreeBSD_version < 700000
     XPT_DONE(sp, ccb);
#else
     xpt_done(ccb);
#endif
     return;
}
Beispiel #10
0
static void
tws_action(struct cam_sim *sim, union ccb *ccb)
{
    struct tws_softc *sc = (struct tws_softc *)cam_sim_softc(sim);


    switch( ccb->ccb_h.func_code ) {
        case XPT_SCSI_IO:   
        {
            if ( tws_execute_scsi(sc, ccb) ) 
                TWS_TRACE_DEBUG(sc, "execute scsi failed", 0, 0);
            break;
        }
        case XPT_ABORT:
        {
            TWS_TRACE_DEBUG(sc, "abort i/o", 0, 0);
            ccb->ccb_h.status = CAM_UA_ABORT;
            xpt_done(ccb);
            break;
        }
        case XPT_RESET_BUS:
        {
            TWS_TRACE_DEBUG(sc, "reset bus", sim, ccb);
            break;
        }
        case XPT_SET_TRAN_SETTINGS:
        {
            TWS_TRACE_DEBUG(sc, "set tran settings", sim, ccb);
            ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
            xpt_done(ccb);

            break;
        }
        case XPT_GET_TRAN_SETTINGS:
        {
            TWS_TRACE_DEBUG(sc, "get tran settings", sim, ccb);

#if (__FreeBSD_version >= 700000 )
            ccb->cts.protocol = PROTO_SCSI;
            ccb->cts.protocol_version = SCSI_REV_2;
            ccb->cts.transport = XPORT_SPI;
            ccb->cts.transport_version = 2;

            ccb->cts.xport_specific.spi.valid = CTS_SPI_VALID_DISC;
            ccb->cts.xport_specific.spi.flags = CTS_SPI_FLAGS_DISC_ENB;
            ccb->cts.proto_specific.scsi.valid = CTS_SCSI_VALID_TQ;
            ccb->cts.proto_specific.scsi.flags = CTS_SCSI_FLAGS_TAG_ENB;
#else
            ccb->cts.valid = (CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID);
            ccb->cts.flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
#endif
            ccb->ccb_h.status = CAM_REQ_CMP;
            xpt_done(ccb);

            break;
        }
        case XPT_CALC_GEOMETRY:
        {
            TWS_TRACE_DEBUG(sc, "calc geometry(ccb,block-size)", ccb, 
                                          ccb->ccg.block_size);
            cam_calc_geometry(&ccb->ccg, 1/* extended */);
            xpt_done(ccb);

            break;
        }
        case XPT_PATH_INQ:
        {
            TWS_TRACE_DEBUG(sc, "path inquiry", sim, ccb);
            ccb->cpi.version_num = 1;
            ccb->cpi.hba_inquiry = 0;
            ccb->cpi.target_sprt = 0;
            ccb->cpi.hba_misc = 0;
            ccb->cpi.hba_eng_cnt = 0;
            ccb->cpi.max_target = TWS_MAX_NUM_UNITS;
            ccb->cpi.max_lun = TWS_MAX_NUM_LUNS - 1;
            ccb->cpi.unit_number = cam_sim_unit(sim);
            ccb->cpi.bus_id = cam_sim_bus(sim);
            ccb->cpi.initiator_id = TWS_SCSI_INITIATOR_ID;
            ccb->cpi.base_transfer_speed = 6000000;
            strncpy(ccb->cpi.sim_vid, "FreeBSD", SIM_IDLEN);
            strncpy(ccb->cpi.hba_vid, "3ware", HBA_IDLEN);
            strncpy(ccb->cpi.dev_name, cam_sim_name(sim), DEV_IDLEN);
#if (__FreeBSD_version >= 700000 )
            ccb->cpi.transport = XPORT_SPI;
            ccb->cpi.transport_version = 2;
            ccb->cpi.protocol = PROTO_SCSI;
            ccb->cpi.protocol_version = SCSI_REV_2;
            ccb->cpi.maxio = TWS_MAX_IO_SIZE;
#endif
            ccb->ccb_h.status = CAM_REQ_CMP;
            xpt_done(ccb);

            break;
        }
        default:
            TWS_TRACE_DEBUG(sc, "default", sim, ccb);
            ccb->ccb_h.status = CAM_REQ_INVALID;
            xpt_done(ccb);
            break;
    }
}
Beispiel #11
0
static void
ahbaction(struct cam_sim *sim, union ccb *ccb)
{
	struct	ahb_softc *ahb;

	CAM_DEBUG(ccb->ccb_h.path, CAM_DEBUG_TRACE, ("ahbaction\n"));
	
	ahb = (struct ahb_softc *)cam_sim_softc(sim);
	
	switch (ccb->ccb_h.func_code) {
	/* Common cases first */
	case XPT_SCSI_IO:	/* Execute the requested I/O operation */
	{
		struct ecb *ecb;
		struct hardware_ecb *hecb;

		/*
		 * get an ecb to use.
		 */
		if ((ecb = ahbecbget(ahb)) == NULL) {
			/* Should never occur */
			panic("Failed to get an ecb");
		}

		/*
		 * So we can find the ECB when an abort is requested
		 */
		ecb->ccb = ccb;
		ccb->ccb_h.ccb_ecb_ptr = ecb;
		ccb->ccb_h.ccb_ahb_ptr = ahb;

		/*
		 * Put all the arguments for the xfer in the ecb
		 */
		hecb = &ecb->hecb;
		hecb->opcode = ECBOP_INITIATOR_SCSI_CMD;
		hecb->flag_word1 = FW1_AUTO_REQUEST_SENSE
				 | FW1_ERR_STATUS_BLK_ONLY;
		hecb->flag_word2 = ccb->ccb_h.target_lun
				 | FW2_NO_RETRY_ON_BUSY;
		if ((ccb->ccb_h.flags & CAM_TAG_ACTION_VALID) != 0) {
			hecb->flag_word2 |= FW2_TAG_ENB
					 | ((ccb->csio.tag_action & 0x3)
					    << FW2_TAG_TYPE_SHIFT);
		}
		if ((ccb->ccb_h.flags & CAM_DIS_DISCONNECT) != 0)
			hecb->flag_word2 |= FW2_DISABLE_DISC;
		hecb->sense_len = ccb->csio.sense_len;
		hecb->cdb_len = ccb->csio.cdb_len;
		if ((ccb->ccb_h.flags & CAM_CDB_POINTER) != 0) {
			if ((ccb->ccb_h.flags & CAM_CDB_PHYS) == 0) {
				bcopy(ccb->csio.cdb_io.cdb_ptr,
				      hecb->cdb, hecb->cdb_len);
			} else {
				/* I guess I could map it in... */
				ccb->ccb_h.status = CAM_REQ_INVALID;
				ahbecbfree(ahb, ecb);
				xpt_done(ccb);
				return;
			}
		} else {
			bcopy(ccb->csio.cdb_io.cdb_bytes,
			      hecb->cdb, hecb->cdb_len);
		}

		/*
		 * If we have any data to send with this command,
		 * map it into bus space.
		 */
		if ((ccb->ccb_h.flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
			if ((ccb->ccb_h.flags & CAM_SCATTER_VALID) == 0) {
				/*
				 * We've been given a pointer
				 * to a single buffer.
				 */
				if ((ccb->ccb_h.flags & CAM_DATA_PHYS)==0) {
					int s;
					int error;

					s = splsoftvm();
					error = bus_dmamap_load(
					    ahb->buffer_dmat,
					    ecb->dmamap,
					    ccb->csio.data_ptr,
					    ccb->csio.dxfer_len,
					    ahbexecuteecb,
					    ecb, /*flags*/0);
					if (error == EINPROGRESS) {
						/*
						 * So as to maintain ordering,
						 * freeze the controller queue
						 * until our mapping is
						 * returned.
						 */
						xpt_freeze_simq(ahb->sim, 1);
						ccb->ccb_h.status |=
						    CAM_RELEASE_SIMQ;
					}
					splx(s);
				} else {
					struct bus_dma_segment seg; 

					/* Pointer to physical buffer */
					seg.ds_addr =
					    (bus_addr_t)ccb->csio.data_ptr;
					seg.ds_len = ccb->csio.dxfer_len;
					ahbexecuteecb(ecb, &seg, 1, 0);
				}
			} else {
				struct bus_dma_segment *segs;

				if ((ccb->ccb_h.flags & CAM_DATA_PHYS) != 0)
					panic("ahbaction - Physical segment "
					      "pointers unsupported");

				if ((ccb->ccb_h.flags & CAM_SG_LIST_PHYS) == 0)
					panic("btaction - Virtual segment "
					      "addresses unsupported");

				/* Just use the segments provided */
				segs = (struct bus_dma_segment *)
				    ccb->csio.data_ptr;
				ahbexecuteecb(ecb, segs, ccb->csio.sglist_cnt,
					     0);
			}
		} else {
			ahbexecuteecb(ecb, NULL, 0, 0);
		}
		break;
	}
	case XPT_EN_LUN:		/* Enable LUN as a target */
	case XPT_TARGET_IO:		/* Execute target I/O request */
	case XPT_ACCEPT_TARGET_IO:	/* Accept Host Target Mode CDB */
	case XPT_CONT_TARGET_IO:	/* Continue Host Target I/O Connection*/
	case XPT_ABORT:			/* Abort the specified CCB */
		/* XXX Implement */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	case XPT_SET_TRAN_SETTINGS:
	{
		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
		xpt_done(ccb);
		break;
	}
	case XPT_GET_TRAN_SETTINGS:
	/* Get default/user set transfer settings for the target */
	{
		struct	ccb_trans_settings *cts = &ccb->cts;
		u_int	target_mask = 0x01 << ccb->ccb_h.target_id;
		struct ccb_trans_settings_scsi *scsi =
		    &cts->proto_specific.scsi;
		struct ccb_trans_settings_spi *spi =
		    &cts->xport_specific.spi;

		if (cts->type == CTS_TYPE_USER_SETTINGS) {
			cts->protocol = PROTO_SCSI;
			cts->protocol_version = SCSI_REV_2;
			cts->transport = XPORT_SPI;
			cts->transport_version = 2;

			scsi->flags &= ~CTS_SCSI_FLAGS_TAG_ENB;
			spi->flags &= ~CTS_SPI_FLAGS_DISC_ENB;
			if ((ahb->disc_permitted & target_mask) != 0)
				spi->flags |= CTS_SPI_FLAGS_DISC_ENB;
			if ((ahb->tags_permitted & target_mask) != 0)
				scsi->flags |= CTS_SCSI_FLAGS_TAG_ENB;
			spi->bus_width = MSG_EXT_WDTR_BUS_8_BIT;
			spi->sync_period = 25; /* 10MHz */

			if (spi->sync_period != 0)
				spi->sync_offset = 15;

			spi->valid = CTS_SPI_VALID_SYNC_RATE
				   | CTS_SPI_VALID_SYNC_OFFSET
				   | CTS_SPI_VALID_BUS_WIDTH
				   | CTS_SPI_VALID_DISC;
			scsi->valid = CTS_SCSI_VALID_TQ;
			ccb->ccb_h.status = CAM_REQ_CMP;
		} else {
			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
		}
		xpt_done(ccb);
		break;
	}
	case XPT_RESET_DEV:	/* Bus Device Reset the specified SCSI device */
	{
		int i;
		int s;

		s = splcam();
		ahb->immed_cmd = IMMED_RESET;
		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ccb->ccb_h.target_id);
		/* Poll for interrupt completion */
		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--) {
			DELAY(1000);
			ahbintr(cam_sim_softc(sim));
		}
		splx(s);
		break;
	}
	case XPT_CALC_GEOMETRY:
	{
		cam_calc_geometry(&ccb->ccg, ahb->extended_trans); 
		xpt_done(ccb);
		break;
	}
	case XPT_RESET_BUS:		/* Reset the specified SCSI bus */
	{
		int i;

		ahb->immed_cmd = IMMED_RESET;
		ahbqueuembox(ahb, IMMED_RESET, ATTN_IMMED|ahb->scsi_id);
		/* Poll for interrupt completion */
		for (i = 1000; ahb->immed_cmd != 0 && i != 0; i--)
			DELAY(1000);
		ccb->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}
	case XPT_TERM_IO:		/* Terminate the I/O process */
		/* XXX Implement */
		ccb->ccb_h.status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	case XPT_PATH_INQ:		/* Path routing inquiry */
	{
		struct ccb_pathinq *cpi = &ccb->cpi;
		
		cpi->version_num = 1; /* XXX??? */
		cpi->hba_inquiry = PI_SDTR_ABLE|PI_TAG_ABLE;
		cpi->target_sprt = 0;
		cpi->hba_misc = 0;
		cpi->hba_eng_cnt = 0;
		cpi->max_target = 7;
		cpi->max_lun = 7;
		cpi->initiator_id = ahb->scsi_id;
		cpi->bus_id = cam_sim_bus(sim);
		cpi->base_transfer_speed = 3300;
		strncpy(cpi->sim_vid, "FreeBSD", SIM_IDLEN);
		strncpy(cpi->hba_vid, "Adaptec", HBA_IDLEN);
		strncpy(cpi->dev_name, cam_sim_name(sim), DEV_IDLEN);
		cpi->unit_number = cam_sim_unit(sim);
                cpi->transport = XPORT_SPI;
                cpi->transport_version = 2;
                cpi->protocol = PROTO_SCSI;
                cpi->protocol_version = SCSI_REV_2;
		cpi->ccb_h.status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}
#if 0
	/* Need these??? */
        case XPT_IMMED_NOTIFY:		/* Notify Host Target driver of event */
        case XPT_NOTIFY_ACK:		/* Acknowledgement of event */
#endif
	default:
		ccb->ccb_h.status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	}
}
Beispiel #12
0
/*
 * Function name:	twa_action
 * Description:		Driver entry point for CAM's use.
 *
 * Input:		sim	-- sim corresponding to the ctlr
 *			ccb	-- ptr to CAM request
 * Output:		None
 * Return value:	None
 */
void
twa_action(struct cam_sim *sim, union ccb *ccb)
{
	struct twa_softc	*sc = (struct twa_softc *)cam_sim_softc(sim);
	struct ccb_hdr		*ccb_h = &(ccb->ccb_h);

	switch (ccb_h->func_code) {
	case XPT_SCSI_IO:	/* SCSI I/O */
	{
		struct twa_request	*tr;

		if ((sc->twa_state & TWA_STATE_SIMQ_FROZEN) ||
				((tr = twa_get_request(sc)) == NULL)) {
			twa_dbg_dprint(2, sc, "simq frozen/Cannot get request pkt.");
			/*
			 * Freeze the simq to maintain ccb ordering.  The next
			 * ccb that gets completed will unfreeze the simq.
			 */
			twa_disallow_new_requests(sc);
			ccb_h->status |= CAM_REQUEUE_REQ;
			xpt_done(ccb);
			break;
		}
		tr->tr_cmd_pkt_type |= TWA_CMD_PKT_TYPE_EXTERNAL;
		tr->tr_private = ccb;
		tr->tr_callback = twa_complete_io;
		if (twa_execute_scsi(tr, ccb))
			twa_release_request(tr);
		break;
	}

	case XPT_ABORT:
		twa_dbg_dprint(2, sc, "Abort request");
		ccb_h->status = CAM_UA_ABORT;
		xpt_done(ccb);
		break;

	case XPT_RESET_BUS:
		twa_printf(sc, "Reset Bus request from CAM...\n");
		if (twa_reset(sc)) {
			twa_printf(sc, "Reset Bus failed!\n");
			ccb_h->status = CAM_REQ_CMP_ERR;
		}
		else
			ccb_h->status = CAM_REQ_CMP;

		xpt_done(ccb);
		break;

	case XPT_SET_TRAN_SETTINGS:
		twa_dbg_dprint(3, sc, "XPT_SET_TRAN_SETTINGS");

		/*
		 * This command is not supported, since it's very specific
		 * to SCSI, and we are doing ATA.
		 */
  		ccb_h->status = CAM_FUNC_NOTAVAIL;
  		xpt_done(ccb);
  		break;

	case XPT_GET_TRAN_SETTINGS: 
	{
		struct ccb_trans_settings	*cts = &ccb->cts;

		twa_dbg_dprint(3, sc, "XPT_GET_TRAN_SETTINGS");
		cts->valid = (CCB_TRANS_DISC_VALID | CCB_TRANS_TQ_VALID);
		cts->flags &= ~(CCB_TRANS_DISC_ENB | CCB_TRANS_TAG_ENB);
		ccb_h->status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}

	case XPT_CALC_GEOMETRY:
		twa_dbg_dprint(3, sc, "XPT_CALC_GEOMETRY request");
		cam_calc_geometry(&ccb->ccg, 1/* extended */);
		xpt_done(ccb);
		break;

	case XPT_PATH_INQ:    /* Path inquiry -- get twa properties */
	{
		struct ccb_pathinq	*path_inq = &ccb->cpi;

		twa_dbg_dprint(3, sc, "XPT_PATH_INQ request");

		path_inq->version_num = 1;
		path_inq->hba_inquiry = 0;
		path_inq->target_sprt = 0;
		path_inq->hba_misc = 0;
		path_inq->hba_eng_cnt = 0;
		path_inq->max_target = TWA_MAX_UNITS;
		path_inq->max_lun = 0;
		path_inq->unit_number = cam_sim_unit(sim);
		path_inq->bus_id = cam_sim_bus(sim);
		path_inq->initiator_id = 12;
		path_inq->base_transfer_speed = 100000;
		strncpy(path_inq->sim_vid, "FreeBSD", SIM_IDLEN);
		strncpy(path_inq->hba_vid, "3ware", HBA_IDLEN);
		strncpy(path_inq->dev_name, cam_sim_name(sim), DEV_IDLEN);
		ccb_h->status = CAM_REQ_CMP;
		xpt_done(ccb);
		break;
	}

	default:
		twa_dbg_dprint(3, sc, "func_code = %x", ccb_h->func_code);
		ccb_h->status = CAM_REQ_INVALID;
		xpt_done(ccb);
		break;
	}
}