Esempio n. 1
0
static int
uftdi_send_data(uftdi_state_t *uf, mblk_t *data)
{
	usb_bulk_req_t *br;
	int len = MBLKL(data);
	int rval;

	USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh,
	    "uftdi_send_data: %d 0x%x 0x%x 0x%x", len, data->b_rptr[0],
	    (len > 1) ? data->b_rptr[1] : 0, (len > 2) ? data->b_rptr[2] : 0);

	ASSERT(!mutex_owned(&uf->uf_lock));

	br = usb_alloc_bulk_req(uf->uf_dip, 0, USB_FLAGS_SLEEP);
	br->bulk_data = data;
	br->bulk_len = len;
	br->bulk_timeout = UFTDI_BULKOUT_TIMEOUT;
	br->bulk_cb = uftdi_bulkout_cb;
	br->bulk_exc_cb = uftdi_bulkout_cb;
	br->bulk_client_private = (usb_opaque_t)uf;
	br->bulk_attributes = USB_ATTRS_AUTOCLEARING;

	rval = usb_pipe_bulk_xfer(uf->uf_bulkout_ph, br, 0);

	if (rval != USB_SUCCESS) {
		USB_DPRINTF_L2(DPRINT_OUT_PIPE, uf->uf_lh,
		    "uftdi_send_data: xfer failed %d", rval);
		br->bulk_data = NULL;
		usb_free_bulk_req(br);
	}

	return (rval);
}
Esempio n. 2
0
/*
 * start receiving data
 */
static int
uftdi_rx_start(uftdi_state_t *uf)
{
	usb_bulk_req_t *br;
	int rval;

	USB_DPRINTF_L4(DPRINT_OUT_PIPE, uf->uf_lh, "uftdi_rx_start");

	ASSERT(mutex_owned(&uf->uf_lock));

	uf->uf_bulkin_state = UFTDI_PIPE_BUSY;
	mutex_exit(&uf->uf_lock);

	br = usb_alloc_bulk_req(uf->uf_dip, uf->uf_xfer_sz, USB_FLAGS_SLEEP);
	br->bulk_len = uf->uf_xfer_sz;
	br->bulk_timeout = UFTDI_BULKIN_TIMEOUT;
	br->bulk_cb = uftdi_bulkin_cb;
	br->bulk_exc_cb = uftdi_bulkin_cb;
	br->bulk_client_private = (usb_opaque_t)uf;
	br->bulk_attributes = USB_ATTRS_AUTOCLEARING | USB_ATTRS_SHORT_XFER_OK;

	rval = usb_pipe_bulk_xfer(uf->uf_bulkin_ph, br, 0);

	if (rval != USB_SUCCESS) {
		USB_DPRINTF_L2(DPRINT_IN_PIPE, uf->uf_lh,
		    "uftdi_rx_start: xfer failed %d", rval);
		usb_free_bulk_req(br);
	}

	mutex_enter(&uf->uf_lock);
	if (rval != USB_SUCCESS)
		uf->uf_bulkin_state = UFTDI_PIPE_IDLE;

	return (rval);
}
Esempio n. 3
0
int
usba10_usb_pipe_bulk_xfer(
	usb_pipe_handle_t	pipe_handle,
	usb_bulk_req_t		*reqp,
	usb_flags_t		flags)
{
	return (usb_pipe_bulk_xfer(pipe_handle, reqp, flags));
}
/*
 * scsa2usb_handle_status_start:
 *	Receive status data
 */
static int
scsa2usb_handle_status_start(scsa2usb_state_t *scsa2usbp,
    usb_bulk_req_t *req)
{
	int rval;

	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
	    "scsa2usb_handle_status_start: req = 0x%p", (void *)req);

	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));

	/* setup up for receiving CSW */
#ifdef	SCSA2USB_BULK_ONLY_TEST
	req->bulk_attributes = 0;
#else
	req->bulk_attributes = USB_ATTRS_SHORT_XFER_OK;
#endif	/* SCSA2USB_BULK_ONLY_TEST */
	req->bulk_len = CSW_LEN;

	SCSA2USB_FREE_MSG(req->bulk_data);
	req->bulk_data = allocb_wait(req->bulk_len,
	    BPRI_LO, STR_NOSIG, NULL);

	/* Issue the request */
	mutex_exit(&scsa2usbp->scsa2usb_mutex);

	ASSERT(req->bulk_timeout);
	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkin_pipe, req,
	    USB_FLAGS_SLEEP);
	mutex_enter(&scsa2usbp->scsa2usb_mutex);

	USB_DPRINTF_L3(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
	    "scsa2usb_handle_status_start: END rval = 0x%x", rval);

	if (rval != USB_SUCCESS) {
		if (scsa2usbp->scsa2usb_pkt_state == SCSA2USB_PKT_PROCESS_CSW) {
			scsa2usb_bulk_only_reset_recovery(scsa2usbp);

			return (rval);
		}

		if (req->bulk_completion_reason == USB_CR_STALL) {
			(void) scsa2usb_clear_ept_stall(scsa2usbp,
			    scsa2usbp->scsa2usb_bulkin_ept.bEndpointAddress,
			    scsa2usbp->scsa2usb_bulkin_pipe, "bulk-in");
		}
	}

	return (rval);
}
/*
 * scsa2usb_bulk_only_transport:
 *	Implements the BO state machine by these steps:
 *	a) Issues CBW to a Bulk Only device.
 *	b) Start Data Phase if applicable
 *	c) Start Status Phase
 *
 *	returns TRAN_* values
 *
 * scsa2usb_bulk_only_state_machine:
 *
 * scsa2usb_bulk_only_transport() handles the normal transitions or
 * continuation after clearing stalls or error recovery.
 *
 * Command Phase:
 *	prepare a valid CBW and transport it on bulk-out pipe
 *	if error on bulkout:
 *		set pkt_reason to CMD_TRAN_ERR
 *		new pkt state is SCSA2USB_PKT_DO_COMP
 *		reset recovery synchronously
 *	else
 *		proceed to data phase
 *
 * Data Phase:
 *	if data in:
 *		setup data in on bulkin
 *	else if data out:
 *		setup data out on bulkout
 *
 *	data: (in)
 *		copy data transferred so far, no more data to transfer
 *
 *		if stall on bulkin pipe
 *			terminate data transfers, set cmd_done
 *			clear stall on bulkin syncrhonously
 *		else if other exception
 *			set pkt_reason to CMD_TRAN_ERR
 *			new pkt state is SCSA2USB_PKT_DO_COMP
 *			reset recovery syncrhonously
 *		else (no error)
 *			receive status
 *
 *	 data: (out)
 *		if stall on bulkout pipe
 *			terminate data transfers, set cmd_done
 *			clear stall on bulkout synchronously USBA
 *		else if other exception
 *			set pkt_reason to CMD_TRAN_ERR
 *			new pkt state is SCSA2USB_PKT_DO_COMP
 *			reset recovery synchronously
 *		else (no error)
 *			receive status
 *
 * Status Phase:
 *
 *	if stall (first attempt)
 *		new pkt state is SCSA2USB_PKT_PROCESS_CSW
 *		setup receiving status on bulkin
 *		if stall (second attempt)
 *			new pkt state is SCSA2USB_PKT_DO_COMP
 *			reset recovery synchronously, we are hosed.
 *		else
 *			goto check CSW
 *	else
 *		goto check CSW
 *
 * check CSW:
 *	- check length equals 13, signature, and matching tag
 *	- check status is less than or equal to 2
 *	- check residue is less than or equal to data length
 *		adjust residue based on if we got valid data
 *
 *	if not OK
 *		new pkt state is SCSA2USB_PKT_DO_COMP
 *		set pkt reason CMD_TRAN_ERR
 *		reset recovery synchronously, we are hosed
 *	else if phase error
 *		new pkt state is SCSA2USB_PKT_DO_COMP
 *		set pkt reason CMD_TRAN_ERR
 *		reset recovery synchronously
 *	else if (status < 2)
 *		if status is equal to 1
 *			set check condition
 *		if residue
 *			calculate residue from data xferred and DataResidue
 *
 *			set pkt_residue
 *		goto  SCSA2USB_PKT_DO_COMP
 *
 * The reset recovery walks sequentially thru device reset, clearing
 * stalls and pipe resets. When the reset recovery completes we return
 * to the taskq thread.
 *
 * Clearing stalls clears the stall condition, resets the pipe, and
 * then returns to the transport.
 */
int
scsa2usb_bulk_only_transport(scsa2usb_state_t *scsa2usbp, scsa2usb_cmd_t *cmd)
{
	int	rval;
	int	nretry;
	usb_bulk_req_t *req;

	ASSERT(mutex_owned(&scsa2usbp->scsa2usb_mutex));

Cmd_Phase:
	/*
	 * Start Command Phase
	 * Initialize a bulk_req_t
	 */
	req = scsa2usb_init_bulk_req(scsa2usbp, USB_BULK_CBWCMD_LEN,
	    SCSA2USB_BULK_PIPE_TIMEOUT, USB_ATTRS_PIPE_RESET, USB_FLAGS_SLEEP);

	scsa2usb_fill_in_cbw(scsa2usbp, cmd, req->bulk_data);	/* Fill CBW */
	SCSA2USB_PRINT_CDB(scsa2usbp, cmd);			/* Print CDB */

	/* Send a Bulk Command Block Wrapper (CBW) to the device */
	mutex_exit(&scsa2usbp->scsa2usb_mutex);

	ASSERT(req->bulk_timeout);
	rval = usb_pipe_bulk_xfer(scsa2usbp->scsa2usb_bulkout_pipe, req,
	    USB_FLAGS_SLEEP);
	mutex_enter(&scsa2usbp->scsa2usb_mutex);

	USB_DPRINTF_L4(DPRINT_MASK_SCSA, scsa2usbp->scsa2usb_log_handle,
	    "scsa2usb_bulk_only_transport: "
	    "sent cmd = 0x%x Tag = 0x%x DataXferLen = 0x%lx rval = %d",
	    cmd->cmd_cdb[SCSA2USB_OPCODE], cmd->cmd_tag, cmd->cmd_xfercount,
	    rval);

	if (rval != USB_SUCCESS) {
		scsa2usb_bulk_only_handle_error(scsa2usbp, req);

		return (TRAN_FATAL_ERROR);
	}

	/* free the data */
	SCSA2USB_FREE_MSG(req->bulk_data);
	req->bulk_data = NULL;

Data_Phase:
	/*
	 * Start Data Phase
	 * re-set timeout
	 */
	req->bulk_timeout = scsa2usb_bulk_timeout(cmd->cmd_timeout);

	/*
	 * we've not transferred any data yet; updated in
	 * scsa2usb_handle_data_done
	 */
	cmd->cmd_resid_xfercount = cmd->cmd_xfercount;

	if (cmd->cmd_xfercount) {
		/* start I/O to/from the device */
		rval = scsa2usb_handle_data_start(scsa2usbp, cmd, req);

		/* handle data returned, if any */
		scsa2usb_handle_data_done(scsa2usbp, cmd, req);

		if (rval != USB_SUCCESS) {
			USB_DPRINTF_L2(DPRINT_MASK_SCSA,
			    scsa2usbp->scsa2usb_log_handle,
			    "data xfer phase, error =  %d, cr = %d",
			    rval, req->bulk_completion_reason);
			/*
			 * we ran into an error
			 */
			if (req->bulk_completion_reason == USB_CR_STALL) {
				if (scsa2usbp->scsa2usb_cur_pkt) {
					scsa2usbp->scsa2usb_cur_pkt->
					    pkt_reason = CMD_TRAN_ERR;
				}
			} else {
				scsa2usb_bulk_only_handle_error(scsa2usbp, req);

				return (TRAN_FATAL_ERROR);
			}
		} /* end of else */

		/* free the data */
		SCSA2USB_FREE_MSG(req->bulk_data);
		req->bulk_data = NULL;
	}

Status_Phase:
	/*
	 * Start status phase
	 * read in CSW
	 */
	for (nretry = 0; nretry < SCSA2USB_STATUS_RETRIES; nretry++) {
		rval = scsa2usb_handle_status_start(scsa2usbp, req);

		if ((rval != USB_SUCCESS) &&
		    (req->bulk_completion_reason == USB_CR_STALL)) {
			/*
			 * We ran into STALL condition here.
			 * If the condition cannot be cleared
			 * successfully, retry for limited times.
			 */
			scsa2usbp->scsa2usb_pkt_state =
			    SCSA2USB_PKT_PROCESS_CSW;
		} else {

			break;
		}
	}

	if (rval == USB_SUCCESS) {
		/* process CSW */
		rval = scsa2usb_handle_csw_result(scsa2usbp, req->bulk_data);
	} else {
		scsa2usb_bulk_only_handle_error(scsa2usbp, req);

		return (TRAN_FATAL_ERROR);
	}

	SCSA2USB_FREE_BULK_REQ(req);	/* free request */

	if ((rval == USB_SUCCESS) &&		/* CSW was ok */
	    (scsa2usbp->scsa2usb_cur_pkt->pkt_reason == CMD_CMPLT) &&
	    (cmd->cmd_xfercount != 0) &&	/* more data to xfer */
	    !cmd->cmd_done) {			/* we aren't done yet */
		scsa2usb_setup_next_xfer(scsa2usbp, cmd);
		goto Cmd_Phase;
	}

	return (rval == USB_SUCCESS ? TRAN_ACCEPT : TRAN_FATAL_ERROR);
}