[<prev] [next>] [day] [month] [year] [list]
Message-Id: <1295595893-23267-1-git-send-email-tlinder@codeaurora.org>
Date: Fri, 21 Jan 2011 09:44:52 +0200
From: Tatyana Brokhman <tlinder@...eaurora.org>
To: gregkh@...e.de
Cc: linux-arm-msm@...r.kernel.org,
Tatyana Brokhman <tlinder@...eaurora.org>,
linux-usb@...r.kernel.org (open list:USB GADGET/PERIPH...),
linux-kernel@...r.kernel.org (open list)
Subject: [RFC/PATCH 2/4] uasp: COMMAND IU handling infrastructure
This patch defines APIs for different COMMAND IUs implementation
Signed-off-by: Tatyana Brokhman <tlinder@...eaurora.org>
---
drivers/usb/gadget/uasp_cmdiu.c | 436 +++++++++++++++++++++++++++++++++++++++
1 files changed, 436 insertions(+), 0 deletions(-)
diff --git a/drivers/usb/gadget/uasp_cmdiu.c b/drivers/usb/gadget/uasp_cmdiu.c
index 8a7b34e..1444d56 100644
--- a/drivers/usb/gadget/uasp_cmdiu.c
+++ b/drivers/usb/gadget/uasp_cmdiu.c
@@ -48,6 +48,53 @@ struct fsg_buffhd *get_buffhd(struct fsg_buffhd *bh)
}
/**
+ * check_cmdiu() - initial verification of the COMMAND IU
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct lun if the COMMAND IU to be checked is addressed
+ * to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be checked.
+ * @needs_medium: Specifies, is the medium needed for the COMMAND IU processing.
+ */
+static uint32_t check_cmdiu(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu,
+ u8 needs_medium)
+{
+ u32 ua_data = 0;
+
+ DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
+
+ if (!curlun || !curlun->lun) {
+ if (cmdiu->cdb[0] != INQUIRY &&
+ cmdiu->cdb[0] != REQUEST_SENSE) {
+ DBG(udev->ucommon->common,
+ "%s() - Logical unit is not supported\n",
+ __func__);
+ return SS_LOGICAL_UNIT_NOT_SUPPORTED;
+ }
+ } else {
+ if (curlun->lun->unit_attention_data &&
+ cmdiu->cdb[0] != INQUIRY &&
+ cmdiu->cdb[0] != REQUEST_SENSE) {
+ DBG(udev->ucommon->common,
+ "%s() - There is an unit attention condition\n",
+ __func__);
+ ua_data = curlun->lun->unit_attention_data;
+ curlun->lun->unit_attention_data = SS_NO_SENSE;
+ return ua_data;
+ }
+ }
+
+ if (curlun && !(curlun->lun->filp) && needs_medium) {
+ DBG(udev->ucommon->common,
+ "%s() - Medium is not present\n", __func__);
+ return SS_MEDIUM_NOT_PRESENT;
+ }
+
+ return SS_NO_SENSE;
+}
+
+/**
* fill_sense_iu() - fills the struct sense_iu with a given values.
* @udev: Programming view of UASP device.
* @siu: Pointer to structure to be filled.
@@ -77,6 +124,330 @@ void fill_sense_iu(struct uasp_dev *udev,
}
/**
+ * do_uasp_inquiry() - performs INQUIRY SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
+ * performed is addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ */
+static int do_uasp_inquiry(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+
+/**
+ * do_uasp_request_sense() - performs REQUEST SENSE SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
+ * performed is addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ */
+static int do_uasp_request_sense(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_test_unit_ready() - performs TEST UNIT READY SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
+ * performed is addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ */
+static int do_uasp_test_unit_ready(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_mode_sense() - performs MODE SENSE(6) and MODE SENSE(10)
+ * SCSI commands.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
+ * performed is addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ */
+static int do_uasp_mode_sense(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_prevent_allow() - performs PREVENT ALLOW MEDIUM REMOVAL SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be
+ * performed is addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ */
+static int do_uasp_prevent_allow(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_read() - performs READ(6), READ(10), READ(12) SCSI commands.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
+ * addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns non zero if usb request(s) should be submitted to PCD after cmdiu
+ * processing, 0 otherwise.
+ */
+static int do_uasp_read(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_read_capacity() - This function performs READ CAPACITY SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
+ * addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ *
+ */
+static int do_uasp_read_capacity(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_read_format_capacities() - performs READ FORMAT CAPACITIES
+ * SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
+ * addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ */
+static int do_uasp_read_format_capacities(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_start_stop() - performs START STOP UNIT SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
+ * addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ *
+ */
+static int do_uasp_start_stop(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_verify() - This function performs VERIFY SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
+ * addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ */
+static int do_uasp_verify(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_write() - This function performs WRITE(6), WRITE(10), WRITE(12)
+ * SCSI commands.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
+ * addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns: 1 if an IN usb request should be submitted to PCD after processing
+ * 2 if an OUT usb request should be submitted to PCD after processing
+ * 0 otherwise.
+ */
+static int do_uasp_write(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * do_uasp_synchronize_cache() - performs SYNCHRONIZE CACHE SCSI command.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
+ * addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ *
+ * Returns 1 if usb request should be submitted to PCD after cmdiu processing,
+ * 0 otherwise.
+ */
+static int do_uasp_synchronize_cache(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ return 0;
+}
+
+/**
+ * process_cmdiu() - This function performs a given COMMAND IU.
+ * @udev: Programming view of UASP device.
+ * @curlun: Pointer to struct uasp_lun if the COMMAND IU to be performed is
+ * addressed to a valid LUN, 0 otherwise.
+ * @cmdiu: COMMAND IU to be performed.
+ */
+static void process_cmdiu(struct uasp_dev *udev,
+ struct uasp_lun *curlun,
+ struct cmd_iu *cmdiu)
+{
+ unsigned long flags;
+ struct sense_iu *siu;
+ struct usb_request *req;
+ int rc = 0;
+
+ DBG(udev->ucommon->common, "%s() Enter. (cmdiu->cdb[0]=%04x)\n",
+ __func__, cmdiu->cdb[0]);
+
+ /* We're using the backing file */
+ down_read(&udev->ucommon->common->filesem);
+ switch (cmdiu->cdb[0]) {
+ case INQUIRY:
+ rc = do_uasp_inquiry(udev, curlun, cmdiu);
+ break;
+ case MODE_SENSE:
+ case MODE_SENSE_10:
+ rc = do_uasp_mode_sense(udev, curlun, cmdiu);
+ break;
+ case ALLOW_MEDIUM_REMOVAL:
+ rc = do_uasp_prevent_allow(udev, curlun, cmdiu);
+ break;
+ case READ_6:
+ case READ_10:
+ case READ_12:
+ rc = do_uasp_read(udev, curlun, cmdiu);
+ break;
+ case READ_CAPACITY:
+ rc = do_uasp_read_capacity(udev, curlun, cmdiu);
+ break;
+ case READ_FORMAT_CAPACITIES:
+ rc = do_uasp_read_format_capacities(udev, curlun, cmdiu);
+ break;
+ case REQUEST_SENSE:
+ rc = do_uasp_request_sense(udev, curlun, cmdiu);
+ break;
+ case START_STOP:
+ rc = do_uasp_start_stop(udev, curlun, cmdiu);
+ break;
+ case SYNCHRONIZE_CACHE:
+ rc = do_uasp_synchronize_cache(udev, curlun, cmdiu);
+ break;
+ case TEST_UNIT_READY:
+ rc = do_uasp_test_unit_ready(udev, curlun, cmdiu);
+ break;
+ case VERIFY:
+ rc = do_uasp_verify(udev, curlun, cmdiu);
+ break;
+ case WRITE_6:
+ case WRITE_10:
+ case WRITE_12:
+ rc = do_uasp_write(udev, curlun, cmdiu);
+ break;
+ case FORMAT_UNIT:
+ case MODE_SELECT:
+ case MODE_SELECT_10:
+ case RELEASE:
+ case RESERVE:
+ case SEND_DIAGNOSTIC:
+ default:
+ ERROR(udev->ucommon->common,
+ "%s(): Unsupported command = %x\n",
+ __func__, cmdiu->cdb[0]);
+ cmdiu->state = COMMAND_STATE_STATUS;
+ siu = (struct sense_iu *)cmdiu->bh->inreq->buf;
+ fill_sense_iu(udev, siu, IUGETW(cmdiu->ip_tag),
+ STATUS_CHECK_CONDITION,
+ SS_INVALID_COMMAND);
+ fill_usb_request(cmdiu->bh->inreq, (void *)siu,
+ UASP_SIZEOF_SENSE_IU, 0,
+ (void *)cmdiu, 0, IUGETW(cmdiu->ip_tag),
+ status_complete);
+ cmdiu->ep = udev->status;
+ rc = 1;
+ break;
+ }
+
+ up_read(&udev->ucommon->common->filesem);
+ if (rc) {
+ req = (rc == 2 ? cmdiu->bh->outreq : cmdiu->bh->inreq);
+ if (usb_ep_queue(cmdiu->ep, req, 0)) {
+ ERROR(udev->ucommon->common,
+ "%s()usb_ep_queue failed\n", __func__);
+ cmdiu->state = COMMAND_STATE_FAILED;
+ } else {
+ DBG(udev->ucommon->common,
+ "%s() - process_cmdiu: queued req to ep\n",
+ __func__);
+ if (curlun) {
+ spin_lock_irqsave(&(curlun->lock), flags);
+ curlun->active_requests++;
+ spin_unlock_irqrestore(&(curlun->lock), flags);
+ } else {
+ spin_lock_irqsave(
+ &(udev->ucommon->common->lock), flags);
+ udev->active_requests++;
+ spin_unlock_irqrestore(
+ &(udev->ucommon->common->lock), flags);
+ }
+ }
+ }
+}
+
+/**
* do_cmdiu() - This function performs the COMMAND IUs from a given queue.
* @udev: Programming view of UASP device.
* @curlun: Pointer to struct uasp_lun if COMMAND IUs from lun::cmd_queue
@@ -85,7 +456,72 @@ void fill_sense_iu(struct uasp_dev *udev,
*/
void do_cmdiu(struct uasp_dev *udev, struct uasp_lun *curlun)
{
+ struct list_head *link;
+ struct cmd_iu *cmdiu, *tmp;
+ unsigned long flags;
+ int cmd_is_active = 0;
+
DBG(udev->ucommon->common, "%s() - Enter\n", __func__);
+
+ /* Select the cmd_queue from which cmdius should be processed */
+ if (curlun)
+ link = &curlun->cmd_queue;
+ else
+ link = &udev->cmd_queue;
+
+ list_for_each_entry_safe(cmdiu, tmp, link, node) {
+ DBG(udev->ucommon->common, "%s() - Rolling over cmdiu queue\n",
+ __func__);
+
+ /*
+ * TODO: this is a workaround. It is added for processing
+ * of only one command in a certain nexus or lun.
+ * Remove this after initial testing.
+ */
+ if (cmd_is_active) {
+ DBG(udev->ucommon->common,
+ "%s() - Cmdiu is on data stage, do not process"
+ " next cmdiu\n", __func__);
+ break;
+ }
+
+ spin_lock_irqsave(&(udev->ucommon->common->lock), flags);
+ if (cmdiu->state == COMMAND_STATE_IDLE) {
+ /* Try to get buffers for cmdiu processing */
+ cmdiu->bh = get_buffhd(udev->ucommon->common->buffhds);
+ spin_unlock_irqrestore(&(udev->ucommon->common->lock),
+ flags);
+
+ if (!cmdiu->bh) {
+ ERROR(udev->ucommon->common,
+ "%s() -Didn't manage to get buffers for "
+ "cmdiu!\n", __func__);
+ continue;
+ }
+ } else if (cmdiu->state == COMMAND_STATE_DATA) {
+ cmd_is_active = 1;
+ if (cmdiu->req_sts == CMD_REQ_COMPLETED)
+ spin_unlock_irqrestore(
+ &(udev->ucommon->common->lock), flags);
+ else {
+ spin_unlock_irqrestore(
+ &(udev->ucommon->common->lock), flags);
+ continue;
+ }
+ cmd_is_active = 0;
+ } else {
+ spin_unlock_irqrestore(&(udev->ucommon->common->lock),
+ flags);
+ continue;
+ }
+
+ process_cmdiu(udev, curlun, cmdiu);
+
+ if (cmdiu->state == COMMAND_STATE_DATA) {
+ cmd_is_active = 1;
+ break;
+ }
+ }
}
--
1.6.3.3
--
Sent by a Consultant for Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists