> Hi, > > Sorry for the late response. I had a few days off. > > On Thu, July 11, 2013, Dolev Raviv wrote: >> > On Tuesday, July 09, 2013, Sujit Reddy Thumma wrote: >> >> From: Dolev Raviv <draviv@xxxxxxxxxxxxxx> >> >> Allow UFS device to complete its initialization and accept >> >> SCSI commands by setting fDeviceInit flag. The device may take >> >> time for this operation and hence the host should poll until >> >> fDeviceInit flag is toggled to zero. This step is mandated by >> >> UFS device specification for device initialization completion. >> >> Signed-off-by: Dolev Raviv <draviv@xxxxxxxxxxxxxx> >> >> Signed-off-by: Sujit Reddy Thumma <sthumma@xxxxxxxxxxxxxx> >> >> --- >> >> drivers/scsi/ufs/ufs.h | 88 +++++++++++++- >> >> drivers/scsi/ufs/ufshcd.c | 292 >> >> ++++++++++++++++++++++++++++++++++++++++++++- >> >> drivers/scsi/ufs/ufshcd.h | 14 ++ >> >> drivers/scsi/ufs/ufshci.h | 2 +- >> >> 4 files changed, 390 insertions(+), 6 deletions(-) >> >> diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h >> >> index 14c0a4e..db5bde4 100644 >> >> --- a/drivers/scsi/ufs/ufs.h >> >> +++ b/drivers/scsi/ufs/ufs.h >> >> @@ -43,6 +43,8 @@ >> >> #define GENERAL_UPIU_REQUEST_SIZE 32 >> >> #define UPIU_HEADER_DATA_SEGMENT_MAX_SIZE ((ALIGNED_UPIU_SIZE) - \ >> >> (GENERAL_UPIU_REQUEST_SIZE)) >> >> +#define QUERY_OSF_SIZE ((GENERAL_UPIU_REQUEST_SIZE) - \ >> >> + (sizeof(struct utp_upiu_header))) >> >> #define UPIU_HEADER_DWORD(byte3, byte2, byte1, byte0)\ >> >> cpu_to_be32((byte3 << 24) | (byte2 << 16) |\ >> >> @@ -68,7 +70,7 @@ enum { >> >> UPIU_TRANSACTION_COMMAND = 0x01, >> >> UPIU_TRANSACTION_DATA_OUT = 0x02, >> >> UPIU_TRANSACTION_TASK_REQ = 0x04, >> >> - UPIU_TRANSACTION_QUERY_REQ = 0x26, >> >> + UPIU_TRANSACTION_QUERY_REQ = 0x16, >> >> }; >> >> /* UTP UPIU Transaction Codes Target to Initiator */ >> >> @@ -97,8 +99,19 @@ enum { >> >> UPIU_TASK_ATTR_ACA = 0x03, >> >> }; >> >> -/* UTP QUERY Transaction Specific Fields OpCode */ >> >> +/* UPIU Query request function */ >> >> enum { >> >> + UPIU_QUERY_FUNC_STANDARD_READ_REQUEST = 0x01, >> >> + UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81, >> >> +}; >> >> + >> >> +/* Flag idn for Query Requests*/ >> >> +enum flag_idn { >> >> + QUERY_FLAG_IDN_FDEVICEINIT = 0x01, >> >> +}; >> >> + >> >> +/* UTP QUERY Transaction Specific Fields OpCode */ >> >> +enum query_opcode { >> >> UPIU_QUERY_OPCODE_NOP = 0x0, >> >> UPIU_QUERY_OPCODE_READ_DESC = 0x1, >> >> UPIU_QUERY_OPCODE_WRITE_DESC = 0x2, >> >> @@ -110,6 +123,21 @@ enum { >> >> UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8, >> >> }; >> >> +/* Query response result code */ >> >> +enum { >> >> + QUERY_RESULT_SUCCESS = 0x00, >> >> + QUERY_RESULT_NOT_READABLE = 0xF6, >> >> + QUERY_RESULT_NOT_WRITEABLE = 0xF7, >> >> + QUERY_RESULT_ALREADY_WRITTEN = 0xF8, >> >> + QUERY_RESULT_INVALID_LENGTH = 0xF9, >> >> + QUERY_RESULT_INVALID_VALUE = 0xFA, >> >> + QUERY_RESULT_INVALID_SELECTOR = 0xFB, >> >> + QUERY_RESULT_INVALID_INDEX = 0xFC, >> >> + QUERY_RESULT_INVALID_IDN = 0xFD, >> >> + QUERY_RESULT_INVALID_OPCODE = 0xFE, >> >> + QUERY_RESULT_GENERAL_FAILURE = 0xFF, >> >> +}; >> >> + >> >> /* UTP Transfer Request Command Type (CT) */ >> >> enum { >> >> UPIU_COMMAND_SET_TYPE_SCSI = 0x0, >> >> @@ -127,6 +155,7 @@ enum { >> >> MASK_SCSI_STATUS = 0xFF, >> >> MASK_TASK_RESPONSE = 0xFF00, >> >> MASK_RSP_UPIU_RESULT = 0xFFFF, >> >> + MASK_QUERY_DATA_SEG_LEN = 0xFFFF, >> >> }; >> >> /* Task management service response */ >> >> @@ -160,13 +189,40 @@ struct utp_upiu_cmd { >> >> }; >> >> /** >> >> + * struct utp_upiu_query - upiu request buffer structure for >> >> + * query request. >> >> + * @opcode: command to perform B-0 >> >> + * @idn: a value that indicates the particular type of data B-1 + * >> @index: Index to further identify data B-2 >> >> + * @selector: Index to further identify data B-3 >> >> + * @reserved_osf: spec reserved field B-4,5 >> >> + * @length: number of descriptor bytes to read/write B-6,7 >> >> + * @value: Attribute value to be written DW-5 >> >> + * @reserved: spec reserved DW-6,7 >> >> + */ >> >> +struct utp_upiu_query { >> >> + u8 opcode; >> >> + u8 idn; >> >> + u8 index; >> >> + u8 selector; >> >> + u16 reserved_osf; >> >> + u16 length; >> >> + u32 value; >> >> + u32 reserved[2]; >> >> +}; >> >> + >> >> +/** >> >> * struct utp_upiu_req - general upiu request structure >> >> * @header:UPIU header structure DW-0 to DW-2 >> >> * @sc: fields structure for scsi command DW-3 to DW-7 >> >> + * @qr: fields structure for query request DW-3 to DW-7 >> >> */ >> >> struct utp_upiu_req { >> >> struct utp_upiu_header header; >> >> - struct utp_upiu_cmd sc; >> >> + union { >> >> + struct utp_upiu_cmd sc; >> >> + struct utp_upiu_query qr; >> >> + }; >> >> }; >> >> /** >> >> @@ -187,10 +243,14 @@ struct utp_cmd_rsp { >> >> * struct utp_upiu_rsp - general upiu response structure >> >> * @header: UPIU header structure DW-0 to DW-2 >> >> * @sr: fields structure for scsi command DW-3 to DW-12 >> >> + * @qr: fields structure for query request DW-3 to DW-7 >> >> */ >> >> struct utp_upiu_rsp { >> >> struct utp_upiu_header header; >> >> - struct utp_cmd_rsp sr; >> >> + union { >> >> + struct utp_cmd_rsp sr; >> >> + struct utp_upiu_query qr; >> >> + }; >> >> }; >> >> /** >> >> @@ -223,4 +283,24 @@ struct utp_upiu_task_rsp { >> >> u32 reserved[3]; >> >> }; >> >> +/** >> >> + * struct ufs_query_req - parameters for building a query request + >> * >> @query_func: UPIU header query function >> >> + * @upiu_req: the query request data >> >> + */ >> >> +struct ufs_query_req { >> >> + u8 query_func; >> >> + struct utp_upiu_query upiu_req; >> >> +}; >> >> + >> >> +/** >> >> + * struct ufs_query_resp - UPIU QUERY >> >> + * @response: device response code >> >> + * @upiu_res: query response data >> >> + */ >> >> +struct ufs_query_res { >> >> + u8 response; >> >> + struct utp_upiu_query upiu_res; >> >> +}; >> >> + >> >> #endif /* End of Header */ >> >> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c >> index 3f482b6..96ccb28 100644 >> >> --- a/drivers/scsi/ufs/ufshcd.c >> >> +++ b/drivers/scsi/ufs/ufshcd.c >> >> @@ -48,6 +48,14 @@ >> >> /* Timeout after 30 msecs if NOP OUT hangs without response */ >> #define >> NOP_OUT_TIMEOUT 30 /* msecs */ >> >> +/* Query request retries */ >> >> +#define QUERY_REQ_RETRIES 10 >> >> +/* Query request timeout */ >> >> +#define QUERY_REQ_TIMEOUT 30 /* msec */ >> >> + >> >> +/* Expose the flag value from utp_upiu_query.value */ >> >> +#define MASK_QUERY_UPIU_FLAG_LOC 0xFF >> >> + >> >> enum { >> >> UFSHCD_MAX_CHANNEL = 0, >> >> UFSHCD_MAX_ID = 1, >> >> @@ -348,6 +356,63 @@ static inline void ufshcd_copy_sense_data(struct >> ufshcd_lrb *lrbp) >> >> } >> >> /** >> >> + * ufshcd_query_to_cpu() - formats the buffer to native cpu endian + >> * >> @response: upiu query response to convert >> >> + */ >> >> +static inline void ufshcd_query_to_cpu(struct utp_upiu_query >> *response) >> >> +{ >> >> + response->length = be16_to_cpu(response->length); >> >> + response->value = be32_to_cpu(response->value); >> >> +} >> >> + >> >> +/** >> >> + * ufshcd_query_to_be() - formats the buffer to big endian >> >> + * @request: upiu query request to convert >> >> + */ >> >> +static inline void ufshcd_query_to_be(struct utp_upiu_query >> *request) +{ >> >> + request->length = cpu_to_be16(request->length); >> >> + request->value = cpu_to_be32(request->value); >> >> +} >> >> + >> >> +/** >> >> + * ufshcd_copy_query_response() - Copy the Query Response and the >> data >> + * descriptor >> >> + * @hba: per adapter instance >> >> + * @lrb - pointer to local reference block >> >> + */ >> >> +static >> >> +void ufshcd_copy_query_response(struct ufs_hba *hba, struct >> ufshcd_lrb >> *lrbp) >> >> +{ >> >> + struct ufs_query_res *query_res = hba->dev_cmd.query.response; + >> >> + /* Get the UPIU response */ >> >> + if (query_res) { >> >> + query_res->response = ufshcd_get_rsp_upiu_result( >> >> + lrbp->ucd_rsp_ptr) >> UPIU_RSP_CODE_OFFSET; >> >> + >> >> + memcpy(&query_res->upiu_res, &lrbp->ucd_rsp_ptr->qr, >> >> + QUERY_OSF_SIZE); >> >> + ufshcd_query_to_cpu(&query_res->upiu_res); >> >> + } >> >> + >> >> + /* Get the descriptor */ >> >> + if (hba->dev_cmd.query.descriptor && lrbp->ucd_rsp_ptr->qr.opcode >> == >> + UPIU_QUERY_OPCODE_READ_DESC) { >> >> + u8 *descp = (u8 *)&lrbp->ucd_rsp_ptr + >> >> + GENERAL_UPIU_REQUEST_SIZE; >> >> + u16 len; >> >> + >> >> + /* data segment length */ >> >> + len = be32_to_cpu(lrbp->ucd_rsp_ptr->header.dword_2) & >> >> + MASK_QUERY_DATA_SEG_LEN; >> >> + >> >> + memcpy(hba->dev_cmd.query.descriptor, descp, >> >> + min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE)); >> >> + } >> >> +} >> >> + >> >> +/** >> >> * ufshcd_hba_capabilities - Read controller capabilities >> >> * @hba: per adapter instance >> >> */ >> >> @@ -629,6 +694,46 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct >> ufshcd_lrb *lrbp, u32 upiu_flags) >> >> (min_t(unsigned short, lrbp->cmd->cmd_len, MAX_CDB_SIZE))); >> >> } >> >> +/** >> >> + * ufshcd_prepare_utp_query_req_upiu() - fills the >> >> utp_transfer_req_desc, >> >> + * for query requsts >> >> + * @hba: UFS hba >> >> + * @lrbp: local reference block pointer >> >> + * @upiu_flags: flags >> >> + */ >> >> +static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba, >> + struct ufshcd_lrb *lrbp, >> >> + u32 upiu_flags) >> >> +{ >> >> + struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr; >> >> + u16 len = hba->dev_cmd.query.request->upiu_req.length; >> >> + u8 *descp = (u8 *)lrbp->ucd_req_ptr + GENERAL_UPIU_REQUEST_SIZE; + >> >> + /* Query request header */ >> >> + ucd_req_ptr->header.dword_0 = UPIU_HEADER_DWORD( >> >> + UPIU_TRANSACTION_QUERY_REQ, upiu_flags, >> >> + lrbp->lun, lrbp->task_tag); >> >> + ucd_req_ptr->header.dword_1 = UPIU_HEADER_DWORD( >> >> + 0, hba->dev_cmd.query.request->query_func, 0, 0); >> >> + >> >> + /* Data segment length */ >> >> + ucd_req_ptr->header.dword_2 = UPIU_HEADER_DWORD( >> >> + 0, 0, len >> 8, (u8)len); >> >> + >> >> + /* Copy the Query Request buffer as is */ >> >> + memcpy(&lrbp->ucd_req_ptr->qr, >> &hba->dev_cmd.query.request->upiu_req, >> + QUERY_OSF_SIZE); >> >> + ufshcd_query_to_be(&lrbp->ucd_req_ptr->qr); >> >> + >> >> + /* Copy the Descriptor */ >> >> + if ((hba->dev_cmd.query.descriptor != NULL) && (len > 0) && >> >> + (hba->dev_cmd.query.request->upiu_req.opcode == >> >> + UPIU_QUERY_OPCODE_WRITE_DESC)) { >> >> + memcpy(descp, hba->dev_cmd.query.descriptor, >> >> + min_t(u16, len, UPIU_HEADER_DATA_SEGMENT_MAX_SIZE)); >> >> + } >> >> +} >> >> + >> >> static inline void ufshcd_prepare_utp_nop_upiu(struct ufshcd_lrb >> *lrbp) >> >> { >> >> struct utp_upiu_req *ucd_req_ptr = lrbp->ucd_req_ptr; >> >> @@ -663,7 +768,10 @@ static int ufshcd_compose_upiu(struct ufs_hba >> *hba, >> >> struct ufshcd_lrb *lrbp) >> >> break; >> >> case UTP_CMD_TYPE_DEV_MANAGE: >> >> ufshcd_prepare_req_desc_hdr(lrbp, &upiu_flags, DMA_NONE); >> >> - if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP) >> >> + if (hba->dev_cmd.type == DEV_CMD_TYPE_QUERY) >> >> + ufshcd_prepare_utp_query_req_upiu( >> >> + hba, lrbp, upiu_flags); >> >> + else if (hba->dev_cmd.type == DEV_CMD_TYPE_NOP) >> >> ufshcd_prepare_utp_nop_upiu(lrbp); >> >> else >> >> ret = -EINVAL; >> >> @@ -831,6 +939,9 @@ ufshcd_dev_cmd_completion(struct ufs_hba *hba, >> struct ufshcd_lrb *lrbp) >> >> __func__, resp); >> >> } >> >> break; >> >> + case UPIU_TRANSACTION_QUERY_RSP: >> >> + ufshcd_copy_query_response(hba, lrbp); >> >> + break; >> >> case UPIU_TRANSACTION_REJECT_UPIU: >> >> /* TODO: handle Reject UPIU Response */ >> >> err = -EPERM; >> >> @@ -941,6 +1052,128 @@ out_put_tag: >> >> } >> >> /** >> >> + * ufshcd_query_request() - API for issuing query request to the >> device. >> >> + * @hba: ufs driver context >> >> + * @query: params for query request >> >> + * @descriptor: buffer for sending/receiving descriptor >> >> + * @retries: number of times to try executing the command >> >> + * >> >> + * All necessary fields for issuing a query and receiving its >> response >> + * are stored in the UFS hba struct. We can use this method since we >> know >> >> + * there is only one active query request or any device management >> command >> >> + * at all times. >> >> + */ >> >> +static int ufshcd_send_query_request(struct ufs_hba *hba, >> >> + struct ufs_query_req *query, >> >> + u8 *descriptor, >> >> + struct ufs_query_res *response) >> >> +{ >> >> + int ret; >> >> + >> >> + BUG_ON(!hba); >> >> + if (!query || !response) { >> >> + dev_err(hba->dev, >> >> + "%s: NULL pointer query = %p, response = %p\n", >> >> + __func__, query, response); >> >> + return -EINVAL; >> >> + } >> >> + >> >> + mutex_lock(&hba->dev_cmd.lock); >> >> + hba->dev_cmd.query.request = query; >> >> + hba->dev_cmd.query.response = response; >> >> + hba->dev_cmd.query.descriptor = descriptor; >> >> + >> >> + ret = ufshcd_exec_dev_cmd(hba, DEV_CMD_TYPE_QUERY, >> >> + QUERY_REQ_TIMEOUT); >> >> + >> >> + hba->dev_cmd.query.request = NULL; >> >> + hba->dev_cmd.query.response = NULL; >> >> + hba->dev_cmd.query.descriptor = NULL; >> >> + mutex_unlock(&hba->dev_cmd.lock); >> >> + >> >> + return ret; >> >> +} >> >> + >> >> +/** >> >> + * ufshcd_query_flag() - Helper function for composing flag query >> requests >> >> + * hba: per-adapter instance >> >> + * query_opcode: flag query to perform >> >> + * idn: flag idn to access >> >> + * flag_res: the flag value after the query request completes >> >> + * >> >> + * Returns 0 for success, non-zero in case of failure >> >> + */ >> >> +static int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode >> opcode, >> >> + enum flag_idn idn, bool *flag_res) >> >> +{ >> >> + struct ufs_query_req *query; >> >> + struct ufs_query_res *response; >> >> + int err = -ENOMEM; >> >> + >> >> + query = kzalloc(sizeof(struct ufs_query_req), GFP_KERNEL); >> >> + if (!query) { >> >> + dev_err(hba->dev, >> >> + "%s: Failed allocating ufs_query_req instance\n", >> >> + __func__); >> >> + goto out_no_mem; >> >> + } >> >> + response = kzalloc(sizeof(struct ufs_query_res), GFP_KERNEL); + if >> (!response) { >> >> + dev_err(hba->dev, >> >> + "%s: Failed allocating ufs_query_res instance\n", >> >> + __func__); >> >> + goto out_free_query; >> >> + } >> > Can't stack local variable be permitted for query and response instead >> of >> > dynamic allocation? >> It can, though I think it is safer this way. In addition, this code is >> not >> a bottle neck. > Yes, once may not be a problem. But I am seeing this function is called > from some loop routine. > Could you explain the reason dynamic allocation is needed? I don't like the idea of allocating it on stack, I suggest to statically allocate it on the query struct. What do you think? > >> >> + >> >> + switch (opcode) { >> >> + case UPIU_QUERY_OPCODE_SET_FLAG: >> >> + case UPIU_QUERY_OPCODE_CLEAR_FLAG: >> >> + case UPIU_QUERY_OPCODE_TOGGLE_FLAG: >> >> + query->query_func = UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST; >> >> + break; >> >> + case UPIU_QUERY_OPCODE_READ_FLAG: >> >> + query->query_func = UPIU_QUERY_FUNC_STANDARD_READ_REQUEST; >> >> + if (!flag_res) { >> >> + /* No dummy reads */ >> >> + dev_err(hba->dev, "%s: Invalid argument for read request\n", >> + __func__); >> >> + err = -EINVAL; >> >> + goto out; >> >> + } >> >> + break; >> >> + default: >> >> + dev_err(hba->dev, >> >> + "%s: Expected query flag opcode but got = %d\n", >> >> + __func__, opcode); >> >> + err = -EINVAL; >> >> + goto out; >> >> + } >> >> + query->upiu_req.opcode = opcode; >> >> + query->upiu_req.idn = idn; >> >> + >> >> + /* Send query request */ >> >> + err = ufshcd_send_query_request(hba, query, NULL, response); >> >> + >> >> + if (err) { >> >> + dev_err(hba->dev, >> >> + "%s: Sending flag query for idn %d failed, err = %d\n", >> >> + __func__, idn, err); >> >> + goto out; >> >> + } >> >> + >> >> + if (flag_res) >> >> + *flag_res = (response->upiu_res.value & >> >> + MASK_QUERY_UPIU_FLAG_LOC) & 0x1; >> >> + >> >> +out: >> >> + kfree(response); >> >> +out_free_query: >> >> + kfree(query); >> >> +out_no_mem: >> >> + return err; >> >> +} >> >> + >> >> +/** >> >> * ufshcd_memory_alloc - allocate memory for host memory space data >> >> structures >> >> * @hba: per adapter instance >> >> * >> >> @@ -1110,6 +1343,59 @@ static int ufshcd_dme_link_startup(struct >> ufs_hba >> >> *hba) >> >> } >> >> /** >> >> + * ufshcd_validate_device_init() - checks device readiness >> >> + * hba: per-adapter instance >> >> + * >> >> + * Set fDeviceInit flag, than, query the flag until the device >> clears the >> >> + * flag. >> >> + */ >> >> +static int ufshcd_validate_device_init(struct ufs_hba *hba) >> > As standard description, this function is for initialization >> completion. >> How about ufshcd_complete_dev_init for function name? >> You have a point. >> >> +{ >> >> + int i, retries, err = 0; >> >> + bool flag_res = 0; >> >> + >> >> + for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { >> >> + /* Set the fDeviceIntit flag */ >> >> + err = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_SET_FLAG, >> >> + QUERY_FLAG_IDN_FDEVICEINIT, &flag_res); >> > There is no need to get flag_res in case set flag. >> > Just passing NULL is good. >> Consider the following scenario: a device is already fully initialized >> when we init the driver, in this case setting the flag will return 0 >> since >> no further initialization is required. This means we don't have to query >> again or to poll for the fDeviceInit because we already now the >> initialization is completed. > It's not clear. > I think it may be a broad interpretation. > What's the meaning of returned flag_res? > 1. original value > 2. value which is applied by setting the fDeviceInit flag > 3. value which is applied by setting the fDeviceInit flag and reset > > In this step, query is not for read-flag but for set-flag. > Above all, spec. mentions polling the fDeviceInit using read-flag > definitively. After reading the spec, I agree, the statement is a little fuzzy. I will change it to null and fix the code according. > >> >> + if (!err || err == -ETIMEDOUT) >> >> + break; >> >> + dev_dbg(hba->dev, "%s: error %d retrying\n", __func__, err); + } >> >> + if (err) { >> >> + dev_err(hba->dev, >> >> + "%s setting fDeviceInit flag failed with error %d\n", >> >> + __func__, err); >> >> + goto out; >> >> + } >> >> + >> >> + /* poll for max. 100 iterations for fDeviceInit flag to clear */ >> + for (i = 0; i < 100 && !err && flag_res; i++) { >> > In first ufshcd_query_flag, if flag_res is updated with '0', this loop >> can't be executed. >> > Of course, we expect that flag_res has '1'. >> In the described case above, this condition allows us to skip the >> polling >> process. >> >> >> + retries = QUERY_REQ_RETRIES; >> >> + for (retries = QUERY_REQ_RETRIES; retries > 0; retries--) { >> >> + err = ufshcd_query_flag(hba, >> >> + UPIU_QUERY_OPCODE_READ_FLAG, >> >> + QUERY_FLAG_IDN_FDEVICEINIT, &flag_res); >> >> + if (!err || err == -ETIMEDOUT) >> >> + break; >> > Normally, ufshcd_query_flag returns '0' to err while flag is not being >> cleared. >> > If these routine is repeated, inner for-loop is just executed and go >> to >> outer loop. >> > What is difference between two for-loop? >> Your analysis was correct, each loop has a different responsibility. The >> outer loop counts the poling retries, while the inner loop is >> responsible >> for passing the query request to the device without errors. So the inner >> loop will execute more then once iff there was an error and the request >> was not executed properly. > I wonder that valid result comes after error is happened and retry is > taken. > Should we allow the retry in case errors? Well, currently all other components, SCSI included, are retrying in case of errors. I don't see a reason why this case should be different. > > Thanks, > Seungwon Jeon > > -- > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > Thanks, Dolev -- QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html