diff --git a/iscsi-scst/kernel/iscsi.c b/iscsi-scst/kernel/iscsi.c index c61c920fa..a0701841f 100644 --- a/iscsi-scst/kernel/iscsi.c +++ b/iscsi-scst/kernel/iscsi.c @@ -3746,6 +3746,11 @@ static struct scst_trace_log iscsi_local_trace_tbl[] = { #define ISCSI_TRACE_TBL_HELP ", d_write, conn, conn_dbg, iov, pdu, net_page" #endif +static uint16_t iscsi_get_scsi_transport_version(struct scst_cmd *scst_cmd) +{ + return 0x0960; /* iSCSI */ +} + struct scst_tgt_template iscsi_template = { .name = "iscsi", .sg_tablesize = 0xFFFF /* no limit */, @@ -3785,6 +3790,7 @@ struct scst_tgt_template iscsi_template = { .task_mgmt_fn_done = iscsi_task_mgmt_fn_done, .report_aen = iscsi_report_aen, .get_initiator_port_transport_id = iscsi_get_initiator_port_transport_id, + .get_scsi_transport_version = iscsi_get_scsi_transport_version, }; static __init int iscsi_run_threads(int count, char *name, int (*fn)(void *)) diff --git a/mvsas_tgt/mv_tgt.c b/mvsas_tgt/mv_tgt.c index 314a8d8f0..ca885e699 100644 --- a/mvsas_tgt/mv_tgt.c +++ b/mvsas_tgt/mv_tgt.c @@ -66,7 +66,7 @@ static void mvst_host_action(struct mvs_info *mvi, enum mvst_tgt_host_action_t action, u8 phyid); static int mvst_start_sas_target(struct mvs_info *mvi, u8 id); static int mvst_restart_free_list(struct mvs_info *mvi, u8 slot_id); - +static uint16_t mvst_get_scsi_transport_version(struct scst_cmd *scst_cmd); struct kmem_cache *mvst_cmd_cachep; struct mvst_msg_queue tgt_msg_queue; @@ -89,12 +89,18 @@ struct scst_tgt_template tgt_template = { .on_free_cmd = mvst_on_free_cmd, .task_mgmt_fn_done = mvst_task_mgmt_fn_done, .report_aen = mvst_report_event, + .get_scsi_transport_version = mvst_get_scsi_transport_version, }; /* * Functions */ +static uint16_t mvst_get_scsi_transport_version(struct scst_cmd *scst_cmd) +{ + return 0x0BE0; /* SAS */ +} + static u64 mvst_get_be_sas_addr(u8 *sas_addr) { u64 lo = cpu_to_be32((u32)(*(u32 *)&sas_addr[0])); diff --git a/qla2x00t/qla2x00-target/qla2x00t.c b/qla2x00t/qla2x00-target/qla2x00t.c index 0efc2a135..339ac5a78 100644 --- a/qla2x00t/qla2x00-target/qla2x00t.c +++ b/qla2x00t/qla2x00-target/qla2x00t.c @@ -96,6 +96,8 @@ static int q2t_cut_cmd_data_head(struct q2t_cmd *cmd, unsigned int offset); static void q2t_clear_tgt_db(struct q2t_tgt *tgt, bool local_only); static void q2t_on_hw_pending_cmd_timeout(struct scst_cmd *scst_cmd); static int q2t_unreg_sess(struct q2t_sess *sess); +static uint16_t q2t_get_scsi_transport_version(struct scst_cmd *scst_cmd); +static uint16_t q2t_get_phys_transport_version(struct scst_cmd *scst_cmd); #ifndef CONFIG_SCST_PROC @@ -170,6 +172,8 @@ static struct scst_tgt_template tgt2x_template = { .on_free_cmd = q2t_on_free_cmd, .task_mgmt_fn_done = q2t_task_mgmt_fn_done, .get_initiator_port_transport_id = q2t_get_initiator_port_transport_id, + .get_scsi_transport_version = q2t_get_scsi_transport_version, + .get_phys_transport_version = q2t_get_phys_transport_version, .on_hw_pending_cmd_timeout = q2t_on_hw_pending_cmd_timeout, .enable_target = q2t_enable_tgt, .is_target_enabled = q2t_is_tgt_enabled, @@ -5503,6 +5507,17 @@ static void q2t_proc_log_entry_clean(struct scst_tgt_template *templ) #endif /* CONFIG_SCST_PROC */ +static uint16_t q2t_get_scsi_transport_version(struct scst_cmd *scst_cmd) +{ + /* FCP-2 (speculative, there's no info what FW supports) */ + return 0x0900; +} + +static uint16_t q2t_get_phys_transport_version(struct scst_cmd *scst_cmd) +{ + return 0x0DA0; /* FC-FS */ +} + static int __init q2t_init(void) { int res = 0; diff --git a/qla_isp/linux/isp_scst.c b/qla_isp/linux/isp_scst.c index fdf58bda1..0003c9cd4 100644 --- a/qla_isp/linux/isp_scst.c +++ b/qla_isp/linux/isp_scst.c @@ -1581,6 +1581,11 @@ out: return (res); } +static uint16_t isp_get_scsi_transport_version(struct scst_cmd *scst_cmd) +{ + return 0x0900; /* FCP-2 */ +} + static struct scst_tgt_template isp_tgt_template = { .sg_tablesize = SG_ALL, /* we set this value lately based on hardware */ @@ -1598,6 +1603,7 @@ static struct scst_tgt_template isp_tgt_template = .rdy_to_xfer = isp_rdy_to_xfer, .on_free_cmd = isp_on_free_cmd, .task_mgmt_fn_done = isp_task_mgmt_fn_done, + .get_scsi_transport_version = isp_get_scsi_transport_version, //.report_aen = isp_report_aen, .get_initiator_port_transport_id = isp_get_initiator_port_transport_id, diff --git a/scst/include/scst.h b/scst/include/scst.h index bb1be2c5e..ee1c2723f 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -884,6 +884,22 @@ struct scst_tgt_template { */ ssize_t (*mgmt_cmd) (char *cmd); + /* + * Should return physical transport version. Used in the corresponding + * INQUIRY version descriptor. See SPC for the list of available codes. + * + * OPTIONAL + */ + uint16_t (*get_phys_transport_version) (struct scst_cmd *cmd); + + /* + * Should return SCSI transport version. Used in the corresponding + * INQUIRY version descriptor. See SPC for the list of available codes. + * + * OPTIONAL + */ + uint16_t (*get_scsi_transport_version) (struct scst_cmd *cmd); + /* * Name of the template. Must be unique to identify * the template. MUST HAVE @@ -2747,6 +2763,12 @@ static inline void scst_cmd_set_ext_cdb(struct scst_cmd *cmd, cmd->ext_cdb_len = ext_cdb_len; } +/* Returns cmd's target */ +static inline struct scst_tgt *scst_cmd_get_tgt(struct scst_cmd *cmd) +{ + return cmd->tgt; +} + /* Returns cmd's session */ static inline struct scst_session *scst_cmd_get_session(struct scst_cmd *cmd) { diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 8e7e5c891..61b79fde6 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -217,6 +217,7 @@ struct scst_vdisk_dev { must be <= SCSI Model + 1 */ char *filename; /* File name, protected by scst_mutex and suspended activities */ + uint16_t command_set_version; unsigned int t10_dev_id_set:1; /* true if t10_dev_id manually set */ char t10_dev_id[16+8+2]; /* T10 device ID */ char usn[MAX_USN_LEN]; @@ -1396,7 +1397,7 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd) goto out_put; } } else { - int len; + int len, num; if (cmd->cdb[2] != 0) { TRACE_DBG("INQUIRY: Unsupported page %x", cmd->cdb[2]); @@ -1433,6 +1434,46 @@ static void vdisk_exec_inquiry(struct scst_cmd *cmd) * aligned. */ memcpy(&buf[32], SCST_FIO_REV, 4); + + /** Version descriptors **/ + + buf[4] += 58 - 36; + num = 0; + + /* SAM-3 T10/1561-D revision 14 */ + buf[58 + num] = 0x0; + buf[58 + num + 1] = 0x76; + num += 2; + + /* Physical transport */ + if (cmd->tgtt->get_phys_transport_version != NULL) { + uint16_t v = cmd->tgtt->get_phys_transport_version(cmd); + if (v != 0) { + *((uint16_t *)&buf[58 + num]) = cpu_to_be16(v); + num += 2; + } + } + + /* SCSI transport */ + if (cmd->tgtt->get_scsi_transport_version != NULL) { + *((uint16_t *)&buf[58 + num]) = + cpu_to_be16(cmd->tgtt->get_scsi_transport_version(cmd)); + num += 2; + } + + /* SPC-3 T10/1416-D revision 23 */ + buf[58 + num] = 0x3; + buf[58 + num + 1] = 0x12; + num += 2; + + /* Device command set */ + if (virt_dev->command_set_version != 0) { + *((uint16_t *)&buf[58 + num]) = + cpu_to_be16(virt_dev->command_set_version); + num += 2; + } + + buf[4] += num; resp_len = buf[4] + 5; } @@ -3216,6 +3257,8 @@ static int vdev_fileio_add_device(const char *device_name, char *params) if (res != 0) goto out; + virt_dev->command_set_version = 0x04C0; /* SBC-3 */ + virt_dev->wt_flag = DEF_WRITE_THROUGH; virt_dev->nv_cache = DEF_NV_CACHE; virt_dev->o_direct_flag = DEF_O_DIRECT; @@ -3277,6 +3320,8 @@ static int vdev_blockio_add_device(const char *device_name, char *params) if (res != 0) goto out; + virt_dev->command_set_version = 0x04C0; /* SBC-3 */ + virt_dev->blockio = 1; res = vdev_parse_add_dev_params(virt_dev, params, allowed_params); @@ -3329,6 +3374,8 @@ static int vdev_nullio_add_device(const char *device_name, char *params) if (res != 0) goto out; + virt_dev->command_set_version = 0x04C0; /* SBC-3 */ + virt_dev->nullio = 1; res = vdev_parse_add_dev_params(virt_dev, params, allowed_params); @@ -3486,6 +3533,8 @@ static ssize_t __vcdrom_add_device(const char *device_name, char *params) if (res != 0) goto out; + virt_dev->command_set_version = 0x02A0; /* MMC-3 */ + virt_dev->rd_only = 1; virt_dev->removable = 1; virt_dev->cdrom_empty = 1; diff --git a/scst_local/scst_local.c b/scst_local/scst_local.c index 5b2dbf3e7..a59c11d94 100644 --- a/scst_local/scst_local.c +++ b/scst_local/scst_local.c @@ -59,7 +59,7 @@ #ifdef CONFIG_SCST_DEBUG #define SCST_LOCAL_DEFAULT_LOG_FLAGS (TRACE_FUNCTION | TRACE_PID | \ - TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_DEBUG | \ + TRACE_LINE | TRACE_OUT_OF_MEM | TRACE_MGMT | TRACE_MGMT_DEBUG | \ TRACE_MINOR | TRACE_SPECIAL) #else # ifdef CONFIG_SCST_TRACING @@ -130,6 +130,8 @@ static int num_aborts; static int num_dev_resets; static int num_target_resets; +static DEFINE_MUTEX(scst_local_mutex); + /* * We put AEN items on a list on the scst_local_host_info structure so they * can be processed via a work function. We do not actually need the LUN, since @@ -155,6 +157,16 @@ struct scst_local_host_info { struct work_struct local_work; spinlock_t lock; struct list_head work_list; + uint16_t scsi_transport_version, phys_transport_version; + uint8_t *transport_id; + int transport_id_len; +}; + +struct scst_local_sess_info { + struct scst_local_host_info *host; + int number; + uint8_t *transport_id; + int transport_id_len; }; #define to_scst_lcl_host(d) \ @@ -185,6 +197,8 @@ struct scst_local_tgt_specific { static struct kmem_cache *tgt_specific_pool; #endif +static atomic_t scst_local_sess_number = ATOMIC_INIT(0); + static LIST_HEAD(scst_local_host_list); static DEFINE_SPINLOCK(scst_local_host_list_lock); @@ -710,14 +724,17 @@ static int scst_local_report_aen(struct scst_aen *aen) { int res = 0; int event_fn = scst_aen_get_event_fn(aen); - struct scst_local_host_info *scst_lcl_host = scst_sess_get_tgt_priv( - scst_aen_get_sess(aen)); - /*__be64 lun = scst_aen_get_lun(aen);*/ + struct scst_local_host_info *scst_lcl_host; + struct scst_local_sess_info *sess; struct scst_local_work_item *work_item = NULL; long unsigned flags; TRACE_ENTRY(); + sess = (struct scst_local_sess_info *)scst_sess_get_tgt_priv( + scst_aen_get_sess(aen)); + scst_lcl_host = sess->host; + switch (event_fn) { case SCST_AEN_SCSI: /* @@ -749,25 +766,16 @@ static int scst_local_report_aen(struct scst_aen *aen) return res; } -static int scst_local_get_initiator_port_transport_id( - struct scst_session *scst_sess, - uint8_t **transport_id) +static int scst_local_get_sas_transport_id( + struct scst_local_sess_info *sess, + uint8_t **transport_id, int *len) { int res = 0; - int tr_id_size = 0, sess = -1, i = 0; + int tr_id_size = 0; uint8_t *tr_id = NULL; - struct scst_local_host_info *scst_lcl_host; TRACE_ENTRY(); - if (scst_sess == NULL) { - res = SCSI_TRANSPORTID_PROTOCOLID_SAS; - goto out; - } - - scst_lcl_host = (struct scst_local_host_info *) - scst_sess_get_tgt_priv(scst_sess); - tr_id_size = 24; /* A SAS TransportID */ tr_id = kzalloc(tr_id_size, GFP_KERNEL); @@ -780,23 +788,6 @@ static int scst_local_get_initiator_port_transport_id( tr_id[0] = 0x00 | SCSI_TRANSPORTID_PROTOCOLID_SAS; - for (i = 0; i < scst_local_num_tgts; i++) { - /* - * We are called before the session is returned below - */ - if (scst_lcl_host->session[i] == NULL) { - sess = i; - break; - } - } - - if (sess == -1) { - printk(KERN_INFO "%s: Unable to find a matching session\n", - __func__); - res = -ENOENT; - goto out; - } - /* * Assemble a valid SAS address = 0x5OOUUIIR12345678 ... Does SCST * have one? @@ -805,13 +796,14 @@ static int scst_local_get_initiator_port_transport_id( tr_id[4] = 0x5F; tr_id[5] = 0xEE; tr_id[6] = 0xDE; - tr_id[7] = 0x40 | ((sess >> 4) & 0x0F); - tr_id[8] = 0x0F | (sess & 0xF0); + tr_id[7] = 0x40 | ((sess->number >> 4) & 0x0F); + tr_id[8] = 0x0F | (sess->number & 0xF0); tr_id[9] = 0xAD; tr_id[10] = 0xE0; tr_id[11] = 0x50; *transport_id = tr_id; + *len = tr_id_size; TRACE_DBG("Created tid '%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X'", tr_id[4], tr_id[5], tr_id[6], tr_id[7], @@ -822,6 +814,53 @@ out: return res; } +static int scst_local_get_initiator_port_transport_id( + struct scst_session *scst_sess, + uint8_t **transport_id) +{ + int res = 0; + int tr_id_size = 0; + uint8_t *tr_id = NULL; + struct scst_local_sess_info *sess; + + TRACE_ENTRY(); + + if (scst_sess == NULL) { + res = SCSI_TRANSPORTID_PROTOCOLID_SAS; + goto out; + } + + sess = (struct scst_local_sess_info *)scst_sess_get_tgt_priv(scst_sess); + + mutex_lock(&scst_local_mutex); + + if (sess->transport_id == NULL) { + res = scst_local_get_sas_transport_id(sess, + transport_id, &tr_id_size); + goto out_unlock; + } + + tr_id_size = sess->transport_id_len; + sBUG_ON(tr_id_size == 0); + + tr_id = kzalloc(tr_id_size, GFP_KERNEL); + if (tr_id == NULL) { + PRINT_ERROR("Allocation of TransportID (size %d) failed", + tr_id_size); + res = -ENOMEM; + goto out; + } + + memcpy(tr_id, sess->transport_id, sess->transport_id_len); + +out_unlock: + mutex_unlock(&scst_local_mutex); + +out: + TRACE_EXIT_RES(res); + return res; +} + static void scst_local_release_adapter(struct device *dev) { struct scst_local_host_info *scst_lcl_host; @@ -831,9 +870,14 @@ static void scst_local_release_adapter(struct device *dev) scst_lcl_host = to_scst_lcl_host(dev); if (scst_lcl_host) { for (i = 0; i < scst_local_num_tgts; i++) - if (scst_lcl_host->session[i]) + if (scst_lcl_host->session[i]) { + struct scst_local_sess_info *sess; + sess = scst_sess_get_tgt_priv( + scst_lcl_host->session[i]); scst_unregister_session( scst_lcl_host->session[i], TRUE, NULL); + kfree(sess); + } scst_unregister_target(scst_lcl_host->target); cancel_work_sync(&scst_lcl_host->local_work); kfree(scst_lcl_host); @@ -858,11 +902,10 @@ static int scst_local_add_adapter(void) TRACE_ENTRY(); - scst_lcl_host = kzalloc(sizeof(struct scst_local_host_info), - GFP_KERNEL); + scst_lcl_host = kzalloc(sizeof(*scst_lcl_host), GFP_KERNEL); if (NULL == scst_lcl_host) { - printk(KERN_ERR "%s out of memory at line %d\n", - __func__, __LINE__); + PRINT_ERROR("Unable to alloc scst_lcl_host (size %d)", + sizeof(*scst_lcl_host)); return -ENOMEM; } @@ -882,17 +925,32 @@ static int scst_local_add_adapter(void) goto cleanup; } + scst_tgt_set_tgt_priv(scst_lcl_host->target, scst_lcl_host); + /* * Create a session for each device */ for (i = 0; i < scst_local_num_tgts; i++) { + struct scst_local_sess_info *sess; + + sess = kzalloc(sizeof(*sess), GFP_KERNEL); + if (NULL == sess) { + PRINT_ERROR("Unable to alloc scst_lcl_host (size %d)", + sizeof(*sess)); + goto cleanup; + } + + sess->host = scst_lcl_host; + sess->number = atomic_inc_return(&scst_local_sess_number); + sprintf(name, "scstlclhst%d:%d", scst_local_add_host, i); scst_lcl_host->session[i] = scst_register_session( scst_lcl_host->target, - 0, name, (void *)scst_lcl_host, + 0, name, (void *)sess, NULL, NULL); if (!scst_lcl_host->session[i]) { printk(KERN_WARNING "scst_register_session failed:\n"); + kfree(sess); error = -1; goto unregister_target; } @@ -1395,12 +1453,259 @@ static void scst_local_targ_task_mgmt_done(struct scst_mgmt_cmd *mgmt_cmd) return; } +#ifndef CONFIG_SCST_PROC + +static ssize_t scst_local_version_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + sprintf(buf, "%s/%s\n", SCST_LOCAL_VERSION, scst_local_version_date); + +#ifdef CONFIG_SCST_EXTRACHECKS + strcat(buf, "EXTRACHECKS\n"); +#endif + +#ifdef CONFIG_SCST_TRACING + strcat(buf, "TRACING\n"); +#endif + +#ifdef CONFIG_SCST_DEBUG + strcat(buf, "DEBUG\n"); +#endif + + TRACE_EXIT(); + return strlen(buf); +} + +static struct kobj_attribute scst_local_version_attr = + __ATTR(version, S_IRUGO, scst_local_version_show, NULL); + +static ssize_t scst_local_scsi_transport_version_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_tgt *scst_tgt; + struct scst_local_host_info *host; + ssize_t size; + + scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + host = (struct scst_local_host_info *)scst_tgt_get_tgt_priv(scst_tgt); + + if (host->scsi_transport_version != 0) + size = sprintf(buf, "0x%x\n%s", host->scsi_transport_version, + SCST_SYSFS_KEY_MARK "\n"); + else + size = sprintf(buf, "0x%x\n", 0x0BE0); /* SAS */ + + return size; +} + +static ssize_t scst_local_scsi_transport_version_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buffer, size_t size) +{ + ssize_t res; + struct scst_tgt *scst_tgt; + struct scst_local_host_info *host; + unsigned long val; + + scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + host = (struct scst_local_host_info *)scst_tgt_get_tgt_priv(scst_tgt); + + res = strict_strtoul(buffer, 0, &val); + if (res != 0) { + PRINT_ERROR("strict_strtoul() for %s failed: %d", buffer, res); + goto out; + } + + host->scsi_transport_version = val; + + res = size; + +out: + return res; +} + +static struct kobj_attribute scst_local_scsi_transport_version_attr = + __ATTR(scsi_transport_version, S_IRUGO| S_IWUSR, + scst_local_scsi_transport_version_show, + scst_local_scsi_transport_version_store); + +static ssize_t scst_local_phys_transport_version_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + struct scst_tgt *scst_tgt; + struct scst_local_host_info *host; + + scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + host = (struct scst_local_host_info *)scst_tgt_get_tgt_priv(scst_tgt); + + return sprintf(buf, "0x%x\n%s", host->phys_transport_version, + (host->phys_transport_version != 0) ? + SCST_SYSFS_KEY_MARK "\n" : ""); +} + +static ssize_t scst_local_phys_transport_version_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buffer, size_t size) +{ + ssize_t res; + struct scst_tgt *scst_tgt; + struct scst_local_host_info *host; + unsigned long val; + + scst_tgt = container_of(kobj, struct scst_tgt, tgt_kobj); + host = (struct scst_local_host_info *)scst_tgt_get_tgt_priv(scst_tgt); + + res = strict_strtoul(buffer, 0, &val); + if (res != 0) { + PRINT_ERROR("strict_strtoul() for %s failed: %d", buffer, res); + goto out; + } + + host->phys_transport_version = val; + + res = size; + +out: + return res; +} + +static struct kobj_attribute scst_local_phys_transport_version_attr = + __ATTR(phys_transport_version, S_IRUGO| S_IWUSR, + scst_local_phys_transport_version_show, + scst_local_phys_transport_version_store); + +static ssize_t scst_local_transport_id_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + ssize_t res; + struct scst_session *scst_sess; + struct scst_local_sess_info *sess; + uint8_t *tr_id; + int tr_id_len, i; + + scst_sess = container_of(kobj, struct scst_session, sess_kobj); + sess = (struct scst_local_sess_info *)scst_sess_get_tgt_priv(scst_sess); + + mutex_lock(&scst_local_mutex); + + if (sess->transport_id != NULL) { + tr_id = sess->transport_id; + tr_id_len = sess->transport_id_len; + } else { + res = scst_local_get_sas_transport_id(sess, &tr_id, &tr_id_len); + if (res != 0) + goto out_unlock; + } + + res = 0; + for (i = 0; i < tr_id_len; i++) + res += sprintf(&buf[res], "%c", tr_id[i]); + + if (sess->transport_id != NULL) + res += sprintf(&buf[res], "\n%s", SCST_SYSFS_KEY_MARK "\n"); + else + kfree(tr_id); + +out_unlock: + mutex_unlock(&scst_local_mutex); + return res; +} + +static ssize_t scst_local_transport_id_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buffer, size_t size) +{ + ssize_t res; + struct scst_session *scst_sess; + struct scst_local_sess_info *sess; + + scst_sess = container_of(kobj, struct scst_session, sess_kobj); + sess = (struct scst_local_sess_info *)scst_sess_get_tgt_priv(scst_sess); + + mutex_lock(&scst_local_mutex); + + if (sess->transport_id != NULL) { + kfree(sess->transport_id); + sess->transport_id = NULL; + sess->transport_id_len = 0; + } + + if (size == 0) + goto out_res; + + sess->transport_id = kzalloc(size, GFP_KERNEL); + if (sess->transport_id == NULL) { + PRINT_ERROR("Allocation of transport_id (size %d) failed", + size); + res = -ENOMEM; + goto out_unlock; + } + + sess->transport_id_len = size; + + memcpy(sess->transport_id, buffer, sess->transport_id_len); + +out_res: + res = size; + +out_unlock: + mutex_unlock(&scst_local_mutex); + + return res; +} + +static struct kobj_attribute scst_local_transport_id_attr = + __ATTR(transport_id, S_IRUGO| S_IWUSR, + scst_local_transport_id_show, + scst_local_transport_id_store); + +static const struct attribute *scst_local_tgtt_attrs[] = { + &scst_local_version_attr.attr, + NULL, +}; + +static const struct attribute *scst_local_tgt_attrs[] = { + &scst_local_scsi_transport_version_attr.attr, + &scst_local_phys_transport_version_attr.attr, + NULL, +}; + +static const struct attribute *scst_local_sess_attrs[] = { + &scst_local_transport_id_attr.attr, + NULL, +}; + +#endif /* CONFIG_SCST_PROC */ + +static uint16_t scst_local_get_scsi_transport_version(struct scst_cmd *scst_cmd) +{ + struct scst_local_host_info *host; + + host = (struct scst_local_host_info *)scst_tgt_get_tgt_priv( + scst_cmd_get_tgt(scst_cmd)); + + if (host->scsi_transport_version == 0) + return 0x0BE0; /* SAS */ + else + return host->scsi_transport_version; +} + +static uint16_t scst_local_get_phys_transport_version(struct scst_cmd *scst_cmd) +{ + struct scst_local_host_info *host; + + host = (struct scst_local_host_info *)scst_tgt_get_tgt_priv( + scst_cmd_get_tgt(scst_cmd)); + + return host->phys_transport_version; +} + static struct scst_tgt_template scst_local_targ_tmpl = { .name = "scst_local_tgt", .sg_tablesize = 0xffff, .xmit_response_atomic = 1, #ifndef CONFIG_SCST_PROC .enabled_attr_not_needed = 1, + .tgtt_attrs = scst_local_tgtt_attrs, + .tgt_attrs = scst_local_tgt_attrs, + .sess_attrs = scst_local_sess_attrs, #endif .detect = scst_local_targ_detect, .release = scst_local_targ_release, @@ -1409,8 +1714,13 @@ static struct scst_tgt_template scst_local_targ_tmpl = { .on_free_cmd = scst_local_targ_on_free_cmd, .task_mgmt_fn_done = scst_local_targ_task_mgmt_done, .report_aen = scst_local_report_aen, - .get_initiator_port_transport_id - = scst_local_get_initiator_port_transport_id, + .get_initiator_port_transport_id = scst_local_get_initiator_port_transport_id, + .get_scsi_transport_version = scst_local_get_scsi_transport_version, + .get_phys_transport_version = scst_local_get_phys_transport_version, +#if defined(CONFIG_SCST_DEBUG) || defined(CONFIG_SCST_TRACING) + .default_trace_flags = SCST_LOCAL_DEFAULT_LOG_FLAGS, + .trace_flags = &trace_flag, +#endif }; /* diff --git a/srpt/src/ib_srpt.c b/srpt/src/ib_srpt.c index 902b13d98..8763e2c2d 100644 --- a/srpt/src/ib_srpt.c +++ b/srpt/src/ib_srpt.c @@ -3495,6 +3495,11 @@ static int srpt_release(struct scst_tgt *scst_tgt) return 0; } +static uint16_t srpt_get_scsi_transport_version(struct scst_cmd *scst_cmd) +{ + return 0x0940; /* SRP */ +} + /* SCST target template for the SRP target implementation. */ static struct scst_tgt_template srpt_template = { .name = DRV_NAME, @@ -3516,6 +3521,7 @@ static struct scst_tgt_template srpt_template = { .on_free_cmd = srpt_on_free_cmd, .task_mgmt_fn_done = srpt_tsk_mgmt_done, .get_initiator_port_transport_id = srpt_get_initiator_port_transport_id, + .get_scsi_transport_version = srpt_get_scsi_transport_version, }; /**