From 341f592a4a6617e2e7231aa4ce71bdf4e1155f08 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Wed, 18 Mar 2009 19:36:01 +0000 Subject: [PATCH] Support for variable lenght CDB added git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@702 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- iscsi-scst/kernel/iscsi.c | 51 +++++++++++++-- iscsi-scst/kernel/nthread.c | 18 ++--- scst/include/scst.h | 49 +++++++++++--- scst/include/scst_user.h | 15 ++++- scst/src/dev_handlers/scst_user.c | 105 +++++++++++++++++++++++++++--- scst/src/scst_mem.h | 5 +- scst/src/scst_targ.c | 4 +- usr/fileio/common.c | 5 +- 8 files changed, 210 insertions(+), 42 deletions(-) diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index de7992c56..5ee6771cb 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -84,13 +84,32 @@ static inline u32 cmnd_read_size(struct iscsi_cmnd *cmnd) struct iscsi_scsi_cmd_hdr *hdr = cmnd_hdr(cmnd); if (hdr->flags & ISCSI_CMD_READ) { - struct iscsi_rlength_ahdr *ahdr = - (struct iscsi_rlength_ahdr *)cmnd->pdu.ahs; + struct iscsi_ahs_hdr *ahdr; if (!(hdr->flags & ISCSI_CMD_WRITE)) return be32_to_cpu(hdr->data_length); - if (ahdr && ahdr->ahstype == ISCSI_AHSTYPE_RLENGTH) - return be32_to_cpu(ahdr->read_length); + + ahdr = (struct iscsi_ahs_hdr *)cmnd->pdu.ahs; + if (ahdr != NULL) { + uint8_t *p = (uint8_t *)ahdr; + int size = 0; + do { + int s; + + ahdr = (struct iscsi_ahs_hdr *)p; + + if (ahdr->ahstype == ISCSI_AHSTYPE_RLENGTH) { + struct iscsi_rlength_ahdr *rh = + (struct iscsi_rlength_ahdr *)ahdr; + return be32_to_cpu(rh->read_length); + } + + s = 3 + be16_to_cpu(ahdr->ahslength); + s = (s + 3) & -4; + size += s; + p += s; + } while (size < cmnd->pdu.ahssize); + } } return 0; } @@ -1280,6 +1299,7 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req) struct iscsi_scsi_cmd_hdr *req_hdr = cmnd_hdr(req); struct scst_cmd *scst_cmd; scst_data_direction dir; + struct iscsi_ahs_hdr *ahdr; int res = 0; TRACE_ENTRY(); @@ -1343,6 +1363,29 @@ static int scsi_cmnd_start(struct iscsi_cmnd *req) /* cmd_sn is already in CPU format converted in check_cmd_sn() */ scst_cmd_set_tgt_sn(scst_cmd, req_hdr->cmd_sn); + ahdr = (struct iscsi_ahs_hdr *)req->pdu.ahs; + if (ahdr != NULL) { + uint8_t *p = (uint8_t *)ahdr; + int size = 0; + do { + int s; + + ahdr = (struct iscsi_ahs_hdr *)p; + + if (ahdr->ahstype == ISCSI_AHSTYPE_CDB) { + struct iscsi_cdb_ahdr *eca = + (struct iscsi_cdb_ahdr *)ahdr; + scst_cmd_set_ext_cdb(scst_cmd, eca->cdb, + be16_to_cpu(ahdr->ahslength) - 1); + break; + } + s = 3 + be16_to_cpu(ahdr->ahslength); + s = (s + 3) & -4; + size += s; + p += s; + } while (size < req->pdu.ahssize); + } + TRACE_DBG("START Command (tag %d, queue_type %d)", req_hdr->itt, scst_cmd->queue_type); req->scst_state = ISCSI_CMD_STATE_RX_CMD; diff --git a/iscsi-scst/kernel/nthread.c b/iscsi-scst/kernel/nthread.c index 0b2d49d87..9432adde0 100644 --- a/iscsi-scst/kernel/nthread.c +++ b/iscsi-scst/kernel/nthread.c @@ -798,20 +798,17 @@ static int recv(struct iscsi_conn *conn) iscsi_conn_init_read(conn, (void __force __user *)&conn->rpadding, psz); conn->read_state = RX_PADDING; - } else if (ddigest) { + } else if (ddigest) conn->read_state = RX_INIT_DDIGEST; - goto init_ddigest; - } else { + else conn->read_state = RX_END; - break; - } + break; } case RX_PADDING: res = do_recv(conn, ddigest ? RX_INIT_DDIGEST : RX_END); if (res <= 0 || conn->read_state != RX_INIT_DDIGEST) break; case RX_INIT_DDIGEST: -init_ddigest: iscsi_conn_init_read(conn, (void __force __user *)&cmnd->ddigest, sizeof(u32)); conn->read_state = RX_DDIGEST; @@ -1511,19 +1508,16 @@ int iscsi_send(struct iscsi_conn *conn) cmnd->pdu.datasize; if (cmnd->conn->write_size != 0) conn->write_state = TX_PADDING; - else if (ddigest) { + else if (ddigest) conn->write_state = TX_INIT_DDIGEST; - goto init_ddigest; - } else { + else conn->write_state = TX_END; - break; - } + break; case TX_PADDING: res = tx_padding(cmnd, ddigest ? TX_INIT_DDIGEST : TX_END); if (res <= 0 || conn->write_state != TX_INIT_DDIGEST) break; case TX_INIT_DDIGEST: -init_ddigest: cmnd->conn->write_size = sizeof(u32); conn->write_state = TX_DDIGEST; case TX_DDIGEST: diff --git a/scst/include/scst.h b/scst/include/scst.h index 01b89b1b3..c942761fe 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -899,7 +899,7 @@ struct scst_dev_type { /* * Name of the dev handler. Must be unique. MUST HAVE. * - * It's SCST_MAX_NAME + few more bytes to match scst_user requirements. + * It's SCST_MAX_NAME + few more bytes to match scst_user expectations. */ char name[SCST_MAX_NAME + 10]; @@ -1235,7 +1235,9 @@ struct scst_cmd { /* CDB and its len */ uint8_t cdb[SCST_MAX_CDB_SIZE]; - int cdb_len; + unsigned short cdb_len; + unsigned short ext_cdb_len; + uint8_t *ext_cdb; enum scst_cdb_flags op_flags; const char *op_name; @@ -1831,8 +1833,8 @@ void scst_unregister_virtual_dev_driver(struct scst_dev_type *dev_type); * same sess. Returns the command on success or NULL otherwise */ struct scst_cmd *scst_rx_cmd(struct scst_session *sess, - const uint8_t *lun, int lun_len, - const uint8_t *cdb, int cdb_len, int atomic); + const uint8_t *lun, int lun_len, const uint8_t *cdb, + int cdb_len, int atomic); /* * Notifies SCST that the driver finished its part of the command @@ -1964,11 +1966,8 @@ static inline int scst_rx_mgmt_fn_lun(struct scst_session *sess, int fn, } /* - * Provides various CDB info - * Parameters: - * cdb_p - pointer to CDB - * dev_type - SCSI device type - * op_flags, direction, transfer_len, cdb_len, op_name - the result (output) + * Provides various info about command's CDB. + * * Returns: 0 on success, <0 if command is unknown, >0 if command is invalid. */ int scst_get_cdb_info(struct scst_cmd *cmd); @@ -2146,6 +2145,38 @@ static inline enum scst_exec_context scst_estimate_context_direct(void) return __scst_estimate_context(1); } +/* Returns cmd's CDB */ +static inline const uint8_t *scst_cmd_get_cdb(struct scst_cmd *cmd) +{ + return cmd->cdb; +} + +/* Returns cmd's CDB length */ +static inline int scst_cmd_get_cdb_len(struct scst_cmd *cmd) +{ + return cmd->cdb_len; +} + +/* Returns cmd's extended CDB */ +static inline const uint8_t *scst_cmd_get_ext_cdb(struct scst_cmd *cmd) +{ + return cmd->ext_cdb; +} + +/* Returns cmd's extended CDB length */ +static inline int scst_cmd_get_ext_cdb_len(struct scst_cmd *cmd) +{ + return cmd->ext_cdb_len; +} + +/* Sets cmd's extended CDB and its length */ +static inline void scst_cmd_set_ext_cdb(struct scst_cmd *cmd, + uint8_t *ext_cdb, unsigned int ext_cdb_len) +{ + cmd->ext_cdb = ext_cdb; + cmd->ext_cdb_len = ext_cdb_len; +} + /* Returns cmd's session */ static inline struct scst_session *scst_cmd_get_session(struct scst_cmd *cmd) { diff --git a/scst/include/scst_user.h b/scst/include/scst_user.h index fadb7c4ff..1386367ef 100644 --- a/scst/include/scst_user.h +++ b/scst/include/scst_user.h @@ -107,7 +107,8 @@ struct scst_user_scsi_cmd_parse { aligned_u64 sess_h; uint8_t cdb[SCST_MAX_CDB_SIZE]; - int32_t cdb_len; + uint16_t cdb_len; + uint16_t ext_cdb_len; int32_t timeout; int32_t bufflen; @@ -126,7 +127,8 @@ struct scst_user_scsi_cmd_alloc_mem { aligned_u64 sess_h; uint8_t cdb[SCST_MAX_CDB_SIZE]; - int32_t cdb_len; + uint16_t cdb_len; + uint16_t ext_cdb_len; int32_t alloc_len; @@ -140,7 +142,8 @@ struct scst_user_scsi_cmd_exec { aligned_u64 sess_h; uint8_t cdb[SCST_MAX_CDB_SIZE]; - int32_t cdb_len; + uint16_t cdb_len; + uint16_t ext_cdb_len; int32_t data_len; int32_t bufflen; @@ -233,6 +236,11 @@ struct scst_user_reply_cmd { }; }; +struct scst_user_get_ext_cdb { + uint32_t cmd_h; + aligned_u64 ext_cdb_buffer; +}; + #define SCST_USER_REGISTER_DEVICE _IOW('u', 1, struct scst_user_dev_desc) #define SCST_USER_UNREGISTER_DEVICE _IO('u', 2) #define SCST_USER_SET_OPTIONS _IOW('u', 3, struct scst_user_opt) @@ -241,6 +249,7 @@ struct scst_user_reply_cmd { #define SCST_USER_REPLY_CMD _IOW('u', 6, struct scst_user_reply_cmd) #define SCST_USER_FLUSH_CACHE _IO('u', 7) #define SCST_USER_DEVICE_CAPACITY_CHANGED _IO('u', 8) +#define SCST_USER_GET_EXTENDED_CDB _IOWR('u', 9, struct scst_user_get_ext_cdb) /* Values for scst_user_get_cmd.subcode */ #define SCST_USER_ATTACH_SESS \ diff --git a/scst/src/dev_handlers/scst_user.c b/scst/src/dev_handlers/scst_user.c index 3b198aa18..42781d334 100644 --- a/scst/src/dev_handlers/scst_user.c +++ b/scst/src/dev_handlers/scst_user.c @@ -643,9 +643,9 @@ static int dev_user_alloc_space(struct scst_user_cmd *ucmd) ucmd->user_cmd.cmd_h = ucmd->h; ucmd->user_cmd.subcode = SCST_USER_ALLOC_MEM; ucmd->user_cmd.alloc_cmd.sess_h = (unsigned long)cmd->tgt_dev; - memcpy(ucmd->user_cmd.alloc_cmd.cdb, cmd->cdb, - min(sizeof(ucmd->user_cmd.alloc_cmd.cdb), sizeof(cmd->cdb))); + memcpy(ucmd->user_cmd.alloc_cmd.cdb, cmd->cdb, cmd->cdb_len); ucmd->user_cmd.alloc_cmd.cdb_len = cmd->cdb_len; + ucmd->user_cmd.alloc_cmd.ext_cdb_len = cmd->ext_cdb_len; ucmd->user_cmd.alloc_cmd.alloc_len = ucmd->buff_cached ? (cmd->sg_cnt << PAGE_SHIFT) : cmd->bufflen; ucmd->user_cmd.alloc_cmd.queue_type = cmd->queue_type; @@ -766,10 +766,9 @@ static int dev_user_parse(struct scst_cmd *cmd) ucmd->user_cmd.cmd_h = ucmd->h; ucmd->user_cmd.subcode = SCST_USER_PARSE; ucmd->user_cmd.parse_cmd.sess_h = (unsigned long)cmd->tgt_dev; - memcpy(ucmd->user_cmd.parse_cmd.cdb, cmd->cdb, - min(sizeof(ucmd->user_cmd.parse_cmd.cdb), - sizeof(cmd->cdb))); + memcpy(ucmd->user_cmd.parse_cmd.cdb, cmd->cdb, cmd->cdb_len); ucmd->user_cmd.parse_cmd.cdb_len = cmd->cdb_len; + ucmd->user_cmd.parse_cmd.ext_cdb_len = cmd->ext_cdb_len; ucmd->user_cmd.parse_cmd.timeout = cmd->timeout / HZ; ucmd->user_cmd.parse_cmd.bufflen = cmd->bufflen; ucmd->user_cmd.parse_cmd.queue_type = cmd->queue_type; @@ -882,16 +881,17 @@ static int dev_user_exec(struct scst_cmd *cmd) if (cmd->data_direction == SCST_DATA_WRITE) dev_user_flush_dcache(ucmd); + BUILD_BUG_ON(sizeof(ucmd->user_cmd.exec_cmd.cdb) != sizeof(cmd->cdb)); + ucmd->user_cmd_payload_len = offsetof(struct scst_user_get_cmd, exec_cmd) + sizeof(ucmd->user_cmd.exec_cmd); ucmd->user_cmd.cmd_h = ucmd->h; ucmd->user_cmd.subcode = SCST_USER_EXEC; ucmd->user_cmd.exec_cmd.sess_h = (unsigned long)cmd->tgt_dev; - memcpy(ucmd->user_cmd.exec_cmd.cdb, cmd->cdb, - min(sizeof(ucmd->user_cmd.exec_cmd.cdb), - sizeof(cmd->cdb))); + memcpy(ucmd->user_cmd.exec_cmd.cdb, cmd->cdb, cmd->cdb_len); ucmd->user_cmd.exec_cmd.cdb_len = cmd->cdb_len; + ucmd->user_cmd.exec_cmd.ext_cdb_len = cmd->ext_cdb_len; ucmd->user_cmd.exec_cmd.bufflen = cmd->bufflen; ucmd->user_cmd.exec_cmd.data_len = cmd->data_len; ucmd->user_cmd.exec_cmd.pbuf = ucmd->ubuff; @@ -1545,6 +1545,90 @@ out: return res; } +static int dev_user_get_ext_cdb(struct file *file, void __user *arg) +{ + int res = 0; + struct scst_user_dev *dev; + struct scst_user_cmd *ucmd; + struct scst_cmd *cmd; + struct scst_user_get_ext_cdb get; + + TRACE_ENTRY(); + + mutex_lock(&dev_priv_mutex); + dev = (struct scst_user_dev *)file->private_data; + res = dev_user_check_reg(dev); + if (unlikely(res != 0)) { + mutex_unlock(&dev_priv_mutex); + goto out; + } + down_read(&dev->dev_rwsem); + mutex_unlock(&dev_priv_mutex); + + res = copy_from_user(&get, arg, sizeof(get)); + if (unlikely(res < 0)) + goto out_up; + + TRACE_MGMT_DBG("Get ext cdb for dev %s", dev->name); + + TRACE_BUFFER("Get ext cdb", &get, sizeof(get)); + + spin_lock_irq(&dev->cmd_lists.cmd_list_lock); + + ucmd = __ucmd_find_hash(dev, get.cmd_h); + if (unlikely(ucmd == NULL)) { + TRACE_MGMT_DBG("cmd_h %d not found", get.cmd_h); + res = -ESRCH; + goto out_unlock; + } + + if (unlikely(ucmd_get_check(ucmd))) { + TRACE_MGMT_DBG("Found being destroyed cmd_h %d", get.cmd_h); + res = -ESRCH; + goto out_unlock; + } + + if ((ucmd->cmd != NULL) && (ucmd->state <= UCMD_STATE_EXECING) && + (ucmd->sent_to_user || ucmd->background_exec)) { + cmd = ucmd->cmd; + scst_cmd_get(cmd); + } else { + TRACE_MGMT_DBG("Invalid ucmd state %d for cmd_h %d", + ucmd->state, get.cmd_h); + res = -EINVAL; + goto out_put; + } + + spin_unlock_irq(&dev->cmd_lists.cmd_list_lock); + + if (cmd == NULL) + goto out_put; + + if (cmd->ext_cdb == NULL) + goto out_cmd_put; + + TRACE_BUFFER("EXT CDB", cmd->ext_cdb, cmd->ext_cdb_len); + res = copy_to_user((void __user *)(unsigned long)get.ext_cdb_buffer, + cmd->ext_cdb, cmd->ext_cdb_len); + +out_cmd_put: + scst_cmd_put(cmd); + +out_put: + ucmd_put(ucmd); + +out_up: + up_read(&dev->dev_rwsem); + +out: + TRACE_EXIT_RES(res); + return res; + +out_unlock: + spin_unlock_irq(&dev->cmd_lists.cmd_list_lock); + goto out_up; +} + static int dev_user_process_scst_commands(struct scst_user_dev *dev) __releases(&dev->cmd_lists.cmd_list_lock) __acquires(&dev->cmd_lists.cmd_list_lock) @@ -1814,6 +1898,11 @@ static long dev_user_ioctl(struct file *file, unsigned int cmd, res = dev_user_reply_cmd(file, (void __user *)arg); break; + case SCST_USER_GET_EXTENDED_CDB: + TRACE_DBG("%s", "GET_EXTENDED_CDB"); + res = dev_user_get_ext_cdb(file, (void __user *)arg); + break; + case SCST_USER_REGISTER_DEVICE: { struct scst_user_dev_desc *dev_desc; diff --git a/scst/src/scst_mem.h b/scst/src/scst_mem.h index 278970e86..03b47dd96 100644 --- a/scst/src/scst_mem.h +++ b/scst/src/scst_mem.h @@ -84,8 +84,9 @@ struct sgv_pool { struct sgv_pool_acc acc; struct sgv_pool_cache_acc cache_acc[SGV_POOL_ELEMENTS]; - char cache_names[SGV_POOL_ELEMENTS][25]; - char name[25]; + /* SCST_MAX_NAME + few more bytes to match scst_user expectations */ + char cache_names[SGV_POOL_ELEMENTS][SCST_MAX_NAME + 10]; + char name[SCST_MAX_NAME + 10]; struct list_head sgv_pool_list_entry; }; diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index d95c9529a..89deb7186 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -269,7 +269,7 @@ void scst_cmd_init_done(struct scst_cmd *cmd, } if (unlikely(cmd->cdb_len == 0)) { - PRINT_ERROR("Wrong CDB len %d, finishing cmd", 0); + PRINT_ERROR("%s", "Wrong CDB len, finishing cmd"); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_opcode)); scst_set_cmd_abnormal_done_state(cmd); @@ -370,7 +370,7 @@ static int scst_pre_parse(struct scst_cmd *cmd) cmd->data_direction = cmd->expected_data_direction; cmd->bufflen = cmd->expected_transfer_len; - /* Restore (likely) lost CDB length */ + /* Restore (possibly) lost CDB length */ cmd->cdb_len = scst_get_cdb_len(cmd->cdb); if (cmd->cdb_len == -1) { PRINT_ERROR("Unable to get CDB length for " diff --git a/usr/fileio/common.c b/usr/fileio/common.c index 3111fb6ae..4eb9ff183 100644 --- a/usr/fileio/common.c +++ b/usr/fileio/common.c @@ -555,8 +555,9 @@ static int do_alloc_mem(struct vdisk_cmd *vcmd) TRACE_ENTRY(); TRACE_MEM("Alloc mem (cmd %d, sess_h %"PRIx64", cdb_len %d, " - "alloc_len %d, queue_type %d, data_direction %d)", cmd->cmd_h, - cmd->alloc_cmd.sess_h, cmd->alloc_cmd.cdb_len, + "ext_cdb_len %d, alloc_len %d, queue_type %d, data_direction " + "%d)", cmd->cmd_h, cmd->alloc_cmd.sess_h, + cmd->alloc_cmd.cdb_len, cmd->alloc_cmd.ext_cdb_len, cmd->alloc_cmd.alloc_len, cmd->alloc_cmd.queue_type, cmd->alloc_cmd.data_direction);