scsi: ufs: add a low-level __ufshcd_issue_tm_cmd helper

Add a helper that takes a utp_task_req_desc and issues it, which will
be useful for UFS bsg support.  Rewrite ufshcd_issue_tm_cmd0x to use
this new helper.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Avri Altman <avri.altman@wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Christoph Hellwig 2018-10-07 17:30:33 +03:00 committed by Martin K. Petersen
parent 391e388f85
commit c6049cd982

View File

@ -633,19 +633,6 @@ static inline int ufshcd_get_tr_ocs(struct ufshcd_lrb *lrbp)
return le32_to_cpu(lrbp->utr_descriptor_ptr->header.dword_2) & MASK_OCS;
}
/**
* ufshcd_get_tmr_ocs - Get the UTMRD Overall Command Status
* @task_req_descp: pointer to utp_task_req_desc structure
*
* This function is used to get the OCS field from UTMRD
* Returns the OCS field in the UTMRD
*/
static inline int
ufshcd_get_tmr_ocs(struct utp_task_req_desc *task_req_descp)
{
return le32_to_cpu(task_req_descp->header.dword_2) & MASK_OCS;
}
/**
* ufshcd_get_tm_free_slot - get a free slot for task management request
* @hba: per adapter instance
@ -4616,37 +4603,6 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
}
}
/**
* ufshcd_task_req_compl - handle task management request completion
* @hba: per adapter instance
* @index: index of the completed request
* @resp: task management service response
*
* Returns non-zero value on error, zero on success
*/
static int ufshcd_task_req_compl(struct ufs_hba *hba, u32 index, u8 *resp)
{
struct utp_task_req_desc *treq = hba->utmrdl_base_addr + index;
unsigned long flags;
int ocs_value;
spin_lock_irqsave(hba->host->host_lock, flags);
/* Clear completed tasks from outstanding_tasks */
__clear_bit(index, &hba->outstanding_tasks);
ocs_value = ufshcd_get_tmr_ocs(treq);
if (ocs_value != OCS_SUCCESS)
dev_err(hba->dev, "%s: failed, ocs = 0x%x\n",
__func__, ocs_value);
else if (resp)
*resp = be32_to_cpu(treq->output_param1) & MASK_TM_SERVICE_RESP;
spin_unlock_irqrestore(hba->host->host_lock, flags);
return ocs_value;
}
/**
* ufshcd_scsi_cmd_status - Update SCSI command result based on SCSI status
* @lrbp: pointer to local reference block of completed command
@ -5604,27 +5560,12 @@ out:
return err;
}
/**
* ufshcd_issue_tm_cmd - issues task management commands to controller
* @hba: per adapter instance
* @lun_id: LUN ID to which TM command is sent
* @task_id: task ID to which the TM command is applicable
* @tm_function: task management function opcode
* @tm_response: task management service response return value
*
* Returns non-zero value on error, zero on success.
*/
static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
u8 tm_function, u8 *tm_response)
static int __ufshcd_issue_tm_cmd(struct ufs_hba *hba,
struct utp_task_req_desc *treq, u8 tm_function)
{
struct utp_task_req_desc *treq;
struct Scsi_Host *host;
struct Scsi_Host *host = hba->host;
unsigned long flags;
int free_slot;
int err;
int task_tag;
host = hba->host;
int free_slot, task_tag, err;
/*
* Get free slot, sleep if slots are unavailable.
@ -5635,24 +5576,11 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
ufshcd_hold(hba, false);
spin_lock_irqsave(host->host_lock, flags);
treq = hba->utmrdl_base_addr + free_slot;
/* Configure task request descriptor */
treq->header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD);
treq->header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
/* Configure task request UPIU */
task_tag = hba->nutrs + free_slot;
treq->req_header.dword_0 = UPIU_HEADER_DWORD(UPIU_TRANSACTION_TASK_REQ,
0, lun_id, task_tag);
treq->req_header.dword_1 = UPIU_HEADER_DWORD(0, tm_function, 0, 0);
/*
* The host shall provide the same value for LUN field in the basic
* header and for Input Parameter.
*/
treq->input_param1 = cpu_to_be32(lun_id);
treq->input_param2 = cpu_to_be32(task_id);
treq->req_header.dword_0 |= cpu_to_be32(task_tag);
memcpy(hba->utmrdl_base_addr + free_slot, treq, sizeof(*treq));
ufshcd_vops_setup_task_mgmt(hba, free_slot, tm_function);
/* send command to the controller */
@ -5682,8 +5610,15 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
__func__, free_slot);
err = -ETIMEDOUT;
} else {
err = ufshcd_task_req_compl(hba, free_slot, tm_response);
err = 0;
memcpy(treq, hba->utmrdl_base_addr + free_slot, sizeof(*treq));
ufshcd_add_tm_upiu_trace(hba, task_tag, "tm_complete");
spin_lock_irqsave(hba->host->host_lock, flags);
__clear_bit(free_slot, &hba->outstanding_tasks);
spin_unlock_irqrestore(hba->host->host_lock, flags);
}
clear_bit(free_slot, &hba->tm_condition);
@ -5694,6 +5629,52 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
return err;
}
/**
* ufshcd_issue_tm_cmd - issues task management commands to controller
* @hba: per adapter instance
* @lun_id: LUN ID to which TM command is sent
* @task_id: task ID to which the TM command is applicable
* @tm_function: task management function opcode
* @tm_response: task management service response return value
*
* Returns non-zero value on error, zero on success.
*/
static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id,
u8 tm_function, u8 *tm_response)
{
struct utp_task_req_desc treq = { { 0 }, };
int ocs_value, err;
/* Configure task request descriptor */
treq.header.dword_0 = cpu_to_le32(UTP_REQ_DESC_INT_CMD);
treq.header.dword_2 = cpu_to_le32(OCS_INVALID_COMMAND_STATUS);
/* Configure task request UPIU */
treq.req_header.dword_0 = cpu_to_be32(lun_id << 8) |
cpu_to_be32(UPIU_TRANSACTION_TASK_REQ << 24);
treq.req_header.dword_1 = cpu_to_be32(tm_function << 16);
/*
* The host shall provide the same value for LUN field in the basic
* header and for Input Parameter.
*/
treq.input_param1 = cpu_to_be32(lun_id);
treq.input_param2 = cpu_to_be32(task_id);
err = __ufshcd_issue_tm_cmd(hba, &treq, tm_function);
if (err == -ETIMEDOUT)
return err;
ocs_value = le32_to_cpu(treq.header.dword_2) & MASK_OCS;
if (ocs_value != OCS_SUCCESS)
dev_err(hba->dev, "%s: failed, ocs = 0x%x\n",
__func__, ocs_value);
else if (tm_response)
*tm_response = be32_to_cpu(treq.output_param1) &
MASK_TM_SERVICE_RESP;
return err;
}
/**
* ufshcd_eh_device_reset_handler - device reset handler registered to
* scsi layer.