Пример #1
0
static int
ld_twa_dobio(struct ld_twa_softc *sc, void *data, size_t datasize,
	     daddr_t blkno, struct buf *bp)
{
	int rv;
	struct twa_request	*tr;
	struct twa_softc *twa;

	twa = device_private(device_parent(sc->sc_ld.sc_dv));

	if ((tr = twa_get_request(twa, 0)) == NULL) {
		return (EAGAIN);
	}
	if (bp->b_flags & B_READ) {
		tr->tr_flags = TWA_CMD_DATA_OUT;
	} else {
		tr->tr_flags = TWA_CMD_DATA_IN;
	}

	tr->tr_data = data;
	tr->tr_length = datasize;
	tr->tr_cmd_pkt_type =
		(TWA_CMD_PKT_TYPE_9K | TWA_CMD_PKT_TYPE_EXTERNAL);

	tr->tr_command->cmd_hdr.header_desc.size_header = 128;

	tr->tr_command->command.cmd_pkt_9k.command.opcode =
		TWA_OP_EXECUTE_SCSI_COMMAND;
	tr->tr_command->command.cmd_pkt_9k.unit =
		sc->sc_hwunit;
	tr->tr_command->command.cmd_pkt_9k.request_id =
		tr->tr_request_id;
	tr->tr_command->command.cmd_pkt_9k.status = 0;
	tr->tr_command->command.cmd_pkt_9k.sgl_entries = 1;
	tr->tr_command->command.cmd_pkt_9k.sgl_offset = 16;

	/* offset from end of hdr = max cdb len */
	ld_twa_scsicmd(sc, tr, bp);

	tr->tr_callback = ld_twa_handler;
	tr->tr_ld_sc = sc;

	tr->bp = bp;

	rv = twa_map_request(tr);

	return (rv);
}
Пример #2
0
static int
ld_twa_flush(struct ld_softc *ld, int flags)
{
	int s, rv = 0;
	struct twa_request *tr;
	struct twa_softc *twa = device_private(device_parent(ld->sc_dv));
	struct ld_twa_softc *sc = (void *)ld;
	struct twa_command_generic *generic_cmd;

	/* Get a request packet. */
	tr = twa_get_request_wait(twa, 0);
	KASSERT(tr != NULL);

	tr->tr_cmd_pkt_type =
		(TWA_CMD_PKT_TYPE_9K | TWA_CMD_PKT_TYPE_EXTERNAL);

	tr->tr_callback = twa_request_wait_handler;
	tr->tr_ld_sc = sc;

	tr->tr_command->cmd_hdr.header_desc.size_header = 128;

	generic_cmd = &(tr->tr_command->command.cmd_pkt_7k.generic);
	generic_cmd->opcode = TWA_OP_FLUSH;
	generic_cmd->size = 2;
	generic_cmd->unit = sc->sc_hwunit;
	generic_cmd->request_id = tr->tr_request_id;
	generic_cmd->sgl_offset = 0;
	generic_cmd->host_id = 0;
	generic_cmd->status = 0;
	generic_cmd->flags = 0;
	generic_cmd->count = 0;
	rv = twa_map_request(tr);
	s = splbio();
	while (tr->tr_status != TWA_CMD_COMPLETE)
		if ((rv = tsleep(tr, PRIBIO, "twaflush", 60 * hz)) != 0)
			break;
	twa_release_request(tr);
	splx(s);

	return (rv);
}
Пример #3
0
/*
 * Function name:	twa_execute_scsi
 * Description:		Build a fw cmd, based on a CAM style ccb, and
 *			send it down.
 *
 * Input:		tr	-- ptr to request pkt
 *			ccb	-- ptr to CAM style ccb
 * Output:		None
 * Return value:	0	-- success
 *			non-zero-- failure
 */
int
twa_execute_scsi(struct twa_request *tr, union ccb *ccb)
{
	struct twa_softc		*sc = tr->tr_sc;
	struct twa_command_packet	*cmdpkt;
	struct twa_command_9k		*cmd9k;
	struct ccb_hdr			*ccb_h = &(ccb->ccb_h);
	struct ccb_scsiio		*csio = &(ccb->csio);
	int				error;

	twa_dbg_dprint(3, sc, "SCSI I/O request 0x%x", 
				csio->cdb_io.cdb_bytes[0]);

	if (ccb_h->target_id >= TWA_MAX_UNITS) {
		twa_dbg_dprint(3, sc, "Invalid target. PTL = %x %x %x",
			ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
		ccb_h->status |= CAM_TID_INVALID;
		if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)
			xpt_done(ccb);
		return(1);
	}
	if (ccb_h->target_lun != 0) {
		twa_dbg_dprint(3, sc, "Invalid lun. PTL = %x %x %x",
			ccb_h->path_id, ccb_h->target_id, ccb_h->target_lun);
		ccb_h->status |= CAM_LUN_INVALID;
		if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)
			xpt_done(ccb);
		return(1);
	}

	if(ccb_h->flags & CAM_CDB_PHYS) {
		twa_printf(sc, "Physical CDB address!\n");
		ccb_h->status = CAM_REQ_CMP_ERR;
		if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)
			xpt_done(ccb);
		return(1);
	}

	/*
	 * We are going to work on this request.  Mark it as enqueued (though
	 * we don't actually queue it...)
	 */
	ccb_h->status |= CAM_SIM_QUEUED;

	if((ccb_h->flags & CAM_DIR_MASK) != CAM_DIR_NONE) {
		if(ccb_h->flags & CAM_DIR_IN)
			tr->tr_flags |= TWA_CMD_DATA_IN;
		else
			tr->tr_flags |= TWA_CMD_DATA_OUT;
	}

	cmdpkt = tr->tr_command;

	cmdpkt->cmd_hdr.header_desc.size_header = 128;
		
	cmd9k = &(cmdpkt->command.cmd_pkt_9k);
	cmd9k->command.opcode = TWA_OP_EXECUTE_SCSI_COMMAND;
	cmd9k->unit = ccb_h->target_id;
	cmd9k->request_id = tr->tr_request_id;
	cmd9k->status = 0;
	cmd9k->sgl_offset = 16; /* offset from end of hdr = max cdb len */

	if(ccb_h->flags & CAM_CDB_POINTER)
		bcopy(csio->cdb_io.cdb_ptr, cmd9k->cdb, csio->cdb_len);
	else
		bcopy(csio->cdb_io.cdb_bytes, cmd9k->cdb, csio->cdb_len);

	if (!(ccb_h->flags & CAM_DATA_PHYS)) {
		/* Virtual data addresses.  Need to convert them... */
		twa_dbg_dprint(3, sc, "XPT_SCSI_IO: Single virtual address!");
		if (!(ccb_h->flags & CAM_SCATTER_VALID)) {
			if (csio->dxfer_len > TWA_MAX_IO_SIZE) {
				twa_printf(sc, "I/O size %d too big.\n",
							csio->dxfer_len);
				ccb_h->status = CAM_REQ_TOO_BIG;
				if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL)
					xpt_done(ccb);
				return(1);
			}

			if ((tr->tr_length = csio->dxfer_len)) {
				tr->tr_data = csio->data_ptr;
				cmd9k->sgl_entries = 1;
			}
		} else {
			twa_printf(sc, "twa_execute_scsi: XPT_SCSI_IO: Got SGList!\n");
			ccb_h->status = CAM_REQ_CMP_ERR;
			if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) {
				xpt_done(ccb);
			}
			return(1);
		}
	} else {
		/* Data addresses are physical. */
		twa_printf(sc, "twa_execute_scsi: XPT_SCSI_IO: Physical data addresses!\n");
		ccb_h->status = CAM_REQ_CMP_ERR;
		if (tr->tr_cmd_pkt_type & TWA_CMD_PKT_TYPE_EXTERNAL) {
			ccb_h->status |= CAM_RELEASE_SIMQ;
			ccb_h->status &= ~CAM_SIM_QUEUED;
			xpt_done(ccb);
		}
		return(1);
	}

	tr->tr_cmd_pkt_type |= TWA_CMD_PKT_TYPE_9K;
	/* twa_setup_data_dmamap will fill in the SGL, and submit the I/O. */
	error = twa_map_request(tr);
	return(error);
}