Esempio n. 1
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);
}
Esempio n. 2
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_CMP_ERR;

	if ((csio->cdb_len > AMR_MAX_CDB_LEN) && (sc->support_ext_cdb == 0 ))
	    ccbh->status = CAM_REQ_CMP_ERR;

	/* 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_CMP_ERR;

	/* 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_CMP_ERR;		
	    if (ccbh->flags & CAM_SCATTER_VALID)	/* we want to do the s/g setup */
		ccbh->status = CAM_REQ_CMP_ERR;
	}

	/*
	 * 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_REQ_CMP_ERR;

	/* 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:
    {
	struct    ccb_calc_geometry *ccg = &ccb->ccg;
	u_int32_t size_in_mb;
	u_int32_t secs_per_cylinder;

	size_in_mb = ccg->volume_size / ((1024L * 1024L) / ccg->block_size);

	if (size_in_mb > 1024) {
	    ccg->heads = 255;
	    ccg->secs_per_track = 63;
	} else {
	    ccg->heads = 64;
	    ccg->secs_per_track = 32;
	}
	secs_per_cylinder = ccg->heads * ccg->secs_per_track;
	ccg->cylinders = ccg->volume_size / secs_per_cylinder;
	ccb->ccb_h.status = CAM_REQ_CMP;
	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;
	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 get from controller? */
	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;

	debug(3, "XPT_GET_TRAN_SETTINGS");

	cts = &(ccb->cts);

	if ((cts->flags & CCB_TRANS_USER_SETTINGS) == 0) {
		ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
		break;
        }

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

	cts->valid = CCB_TRANS_SYNC_RATE_VALID
	    | CCB_TRANS_SYNC_OFFSET_VALID
	    | CCB_TRANS_BUS_WIDTH_VALID
	    | CCB_TRANS_DISC_VALID
	    | CCB_TRANS_TQ_VALID;
	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;
    }
    xpt_done(ccb);
}