From d1e12de804f9d8ad114786ca7c2ce593cba79891 Mon Sep 17 00:00:00 2001 From: "Krishnasamy, Somasundaram" Date: Mon, 28 Feb 2011 18:13:22 -0500 Subject: [SCSI] ses: Avoid kernel panic when lun 0 is not mapped During device discovery, scsi mid layer sends INQUIRY command to LUN 0. If the LUN 0 is not mapped to host, it creates a temporary scsi_device with LUN id 0 and sends REPORT_LUNS command to it. After the REPORT_LUNS succeeds, it walks through the LUN table and adds each LUN found to sysfs. At the end of REPORT_LUNS lun table scan, it will delete the temporary scsi_device of LUN 0. When scsi devices are added to sysfs, it calls add_dev function of all the registered class interfaces. If ses driver has been registered, ses_intf_add() of ses module will be called. This function calls scsi_device_enclosure() to check the inquiry data for EncServ bit. Since inquiry was not allocated for temporary LUN 0 scsi_device, it will cause NULL pointer exception. To fix the problem, sdev->inquiry is checked for NULL before reading it. Signed-off-by: Somasundaram Krishnasamy Signed-off-by: Babu Moger Cc: stable@kernel.org Signed-off-by: James Bottomley --- include/scsi/scsi_device.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index f171c65dc5a8..2d3ec5094685 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -462,7 +462,7 @@ static inline int scsi_device_qas(struct scsi_device *sdev) } static inline int scsi_device_enclosure(struct scsi_device *sdev) { - return sdev->inquiry[6] & (1<<6); + return sdev->inquiry ? (sdev->inquiry[6] & (1<<6)) : 1; } static inline int scsi_device_protection(struct scsi_device *sdev) -- cgit v1.2.3 From 5dd7ed2e811d5cd12f31fb7f0c5ad0107d494a12 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 14 Mar 2011 04:06:01 -0700 Subject: [SCSI] target: Minor sparse warning fixes and annotations This patch addresses the majority of sparse warnings and adds proper locking annotations. It also fixes the dubious one-bit signed bitfield, for which the signed one-bit types can be 0 or -1 which can cause a problem if someone ever checks if (foo->lu_gp_assoc == 1). The current code is fine because everyone just checks zero vs non-zero. But Sparse complains about it so lets change it. The warnings look like this: include/target/target_core_base.h:228:26: error: dubious one-bit signed bitfield Signed-off-by: Dan Carpenter Signed-off-by: Fubo Chen Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_device.c | 1 + drivers/target/target_core_fabric_lib.c | 1 + drivers/target/target_core_pscsi.c | 3 +++ drivers/target/target_core_rd.h | 2 -- drivers/target/target_core_transport.c | 4 +--- include/target/target_core_base.h | 14 +++++++------- include/target/target_core_fabric_ops.h | 2 +- include/target/target_core_transport.h | 4 ++++ 8 files changed, 18 insertions(+), 13 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 9e182bd245f0..3fb8e32506ed 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -589,6 +589,7 @@ static void core_export_port( * Called with struct se_device->se_port_lock spinlock held. */ static void core_release_port(struct se_device *dev, struct se_port *port) + __releases(&dev->se_port_lock) __acquires(&dev->se_port_lock) { /* * Wait for any port reference for PR ALL_TG_PT=1 operation diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index a3c695adabec..d57ad672677f 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 51fd309388fc..7ff6a35f26ac 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c @@ -441,6 +441,7 @@ static struct se_device *pscsi_create_type_disk( struct pscsi_dev_virt *pdv, struct se_subsystem_dev *se_dev, struct se_hba *hba) + __releases(sh->host_lock) { struct se_device *dev; struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; @@ -488,6 +489,7 @@ static struct se_device *pscsi_create_type_rom( struct pscsi_dev_virt *pdv, struct se_subsystem_dev *se_dev, struct se_hba *hba) + __releases(sh->host_lock) { struct se_device *dev; struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; @@ -522,6 +524,7 @@ static struct se_device *pscsi_create_type_other( struct pscsi_dev_virt *pdv, struct se_subsystem_dev *se_dev, struct se_hba *hba) + __releases(sh->host_lock) { struct se_device *dev; struct pscsi_hba_virt *phv = (struct pscsi_hba_virt *)pdv->pdv_se_hba->hba_ptr; diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h index 13badfbaf9c0..3ea19e29d8ec 100644 --- a/drivers/target/target_core_rd.h +++ b/drivers/target/target_core_rd.h @@ -14,8 +14,6 @@ #define RD_BLOCKSIZE 512 #define RD_MAX_SECTORS 1024 -extern struct kmem_cache *se_mem_cache; - /* Used in target_core_init_configfs() for virtual LUN 0 access */ int __init rd_module_init(void); void rd_module_exit(void); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ff9ace01e27a..80df4056f9f1 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -227,8 +227,6 @@ static void transport_remove_cmd_from_queue(struct se_cmd *cmd, static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); static void transport_stop_all_task_timers(struct se_cmd *cmd); -int transport_emulate_control_cdb(struct se_task *task); - int init_se_global(void) { struct se_global *global; @@ -4395,7 +4393,7 @@ out: return -1; } -extern u32 transport_calc_sg_num( +u32 transport_calc_sg_num( struct se_task *task, struct se_mem *in_se_mem, u32 task_offset) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 0828b6c8610a..bc93b7819eba 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -239,7 +239,7 @@ struct t10_alua_lu_gp { } ____cacheline_aligned; struct t10_alua_lu_gp_member { - int lu_gp_assoc:1; + bool lu_gp_assoc; atomic_t lu_gp_mem_ref_cnt; spinlock_t lu_gp_mem_lock; struct t10_alua_lu_gp *lu_gp; @@ -271,7 +271,7 @@ struct t10_alua_tg_pt_gp { } ____cacheline_aligned; struct t10_alua_tg_pt_gp_member { - int tg_pt_gp_assoc:1; + bool tg_pt_gp_assoc; atomic_t tg_pt_gp_mem_ref_cnt; spinlock_t tg_pt_gp_mem_lock; struct t10_alua_tg_pt_gp *tg_pt_gp; @@ -336,7 +336,7 @@ struct t10_pr_registration { int pr_res_type; int pr_res_scope; /* Used for fabric initiator WWPNs using a ISID */ - int isid_present_at_reg:1; + bool isid_present_at_reg; u32 pr_res_mapped_lun; u32 pr_aptpl_target_lun; u32 pr_res_generation; @@ -418,7 +418,7 @@ struct se_transport_task { unsigned long long t_task_lba; int t_tasks_failed; int t_tasks_fua; - int t_tasks_bidi:1; + bool t_tasks_bidi; u32 t_task_cdbs; u32 t_tasks_check; u32 t_tasks_no; @@ -470,7 +470,7 @@ struct se_task { u8 task_flags; int task_error_status; int task_state_flags; - int task_padded_sg:1; + bool task_padded_sg; unsigned long long task_lba; u32 task_no; u32 task_sectors; @@ -583,7 +583,7 @@ struct se_ua { struct se_node_acl { char initiatorname[TRANSPORT_IQN_LEN]; /* Used to signal demo mode created ACL, disabled by default */ - int dynamic_node_acl:1; + bool dynamic_node_acl; u32 queue_depth; u32 acl_index; u64 num_cmds; @@ -632,7 +632,7 @@ struct se_lun_acl { } ____cacheline_aligned; struct se_dev_entry { - int def_pr_registered:1; + bool def_pr_registered; /* See transport_lunflags_table */ u32 lun_flags; u32 deve_cmds; diff --git a/include/target/target_core_fabric_ops.h b/include/target/target_core_fabric_ops.h index f3ac12b019c2..5eb8b1ae59d1 100644 --- a/include/target/target_core_fabric_ops.h +++ b/include/target/target_core_fabric_ops.h @@ -8,7 +8,7 @@ struct target_core_fabric_ops { * for scatterlist chaining using transport_do_task_sg_link(), * disabled by default */ - int task_sg_chaining:1; + bool task_sg_chaining; char *(*get_fabric_name)(void); u8 (*get_fabric_proto_ident)(struct se_portal_group *); char *(*tpg_get_wwn)(struct se_portal_group *); diff --git a/include/target/target_core_transport.h b/include/target/target_core_transport.h index 2e8ec51f0615..59aa464f6ee2 100644 --- a/include/target/target_core_transport.h +++ b/include/target/target_core_transport.h @@ -109,6 +109,8 @@ struct se_mem; struct se_subsystem_api; +extern struct kmem_cache *se_mem_cache; + extern int init_se_global(void); extern void release_se_global(void); extern void init_scsi_index_table(void); @@ -190,6 +192,8 @@ extern void transport_generic_process_write(struct se_cmd *); extern int transport_generic_do_tmr(struct se_cmd *); /* From target_core_alua.c */ extern int core_alua_check_nonop_delay(struct se_cmd *); +/* From target_core_cdb.c */ +extern int transport_emulate_control_cdb(struct se_task *); /* * Each se_transport_task_t can have N number of possible struct se_task's -- cgit v1.2.3 From 35ce9e26d7e0674892f77a9172c898dfcba50064 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:06:02 -0700 Subject: [SCSI] target: Remove spurious double cast from structure macro accessors Reported-by: Fubo Chen Cc: James Bottomley Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- include/target/target_core_base.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index bc93b7819eba..b3a62e451313 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -494,8 +494,8 @@ struct se_task { struct list_head t_state_list; } ____cacheline_aligned; -#define TASK_CMD(task) ((struct se_cmd *)task->task_se_cmd) -#define TASK_DEV(task) ((struct se_device *)task->se_dev) +#define TASK_CMD(task) ((task)->task_se_cmd) +#define TASK_DEV(task) ((task)->se_dev) struct se_cmd { /* SAM response code being sent to initiator */ @@ -551,8 +551,8 @@ struct se_cmd { void (*transport_complete_callback)(struct se_cmd *); } ____cacheline_aligned; -#define T_TASK(cmd) ((struct se_transport_task *)(cmd->t_task)) -#define CMD_TFO(cmd) ((struct target_core_fabric_ops *)cmd->se_tfo) +#define T_TASK(cmd) ((cmd)->t_task) +#define CMD_TFO(cmd) ((cmd)->se_tfo) struct se_tmr_req { /* Task Management function to be preformed */ @@ -615,8 +615,8 @@ struct se_session { struct list_head sess_acl_list; } ____cacheline_aligned; -#define SE_SESS(cmd) ((struct se_session *)(cmd)->se_sess) -#define SE_NODE_ACL(sess) ((struct se_node_acl *)(sess)->se_node_acl) +#define SE_SESS(cmd) ((cmd)->se_sess) +#define SE_NODE_ACL(sess) ((sess)->se_node_acl) struct se_device; struct se_transform_info; @@ -803,8 +803,8 @@ struct se_device { struct list_head g_se_dev_list; } ____cacheline_aligned; -#define SE_DEV(cmd) ((struct se_device *)(cmd)->se_lun->lun_se_dev) -#define SU_DEV(dev) ((struct se_subsystem_dev *)(dev)->se_sub_dev) +#define SE_DEV(cmd) ((cmd)->se_lun->lun_se_dev) +#define SU_DEV(dev) ((dev)->se_sub_dev) #define DEV_ATTRIB(dev) (&(dev)->se_sub_dev->se_dev_attrib) #define DEV_T10_WWN(dev) (&(dev)->se_sub_dev->t10_wwn) @@ -832,7 +832,7 @@ struct se_hba { struct se_subsystem_api *transport; } ____cacheline_aligned; -#define SE_HBA(d) ((struct se_hba *)(d)->se_hba) +#define SE_HBA(dev) ((dev)->se_hba) struct se_lun { /* See transport_lun_status_table */ @@ -852,7 +852,7 @@ struct se_lun { struct se_port *lun_sep; } ____cacheline_aligned; -#define SE_LUN(c) ((struct se_lun *)(c)->se_lun) +#define SE_LUN(cmd) ((cmd)->se_lun) struct scsi_port_stats { u64 cmd_pdus; @@ -919,7 +919,7 @@ struct se_portal_group { struct config_group tpg_param_group; } ____cacheline_aligned; -#define TPG_TFO(se_tpg) ((struct target_core_fabric_ops *)(se_tpg)->se_tpg_tfo) +#define TPG_TFO(se_tpg) ((se_tpg)->se_tpg_tfo) struct se_wwn { struct target_fabric_configfs *wwn_tf; -- cgit v1.2.3 From 5c6cd613196558ba50ba97268b6d225c8d2f56d6 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:06:04 -0700 Subject: [SCSI] target: Convert TMR REQ/RSP definitions to target namespace This patch changes include/target/target_core_tmr.h code to use target specific 'TMR_*' prefixed definitions for fabric independent SCSI Task Management Request/Request naming in include/scsi/scsi.h definitions for mainline target code. Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/target_core_transport.c | 19 +++++-------- include/target/target_core_tmr.h | 52 ++++++++++++++-------------------- 2 files changed, 29 insertions(+), 42 deletions(-) (limited to 'include') diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 80df4056f9f1..20ab27cb3e45 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -5832,31 +5832,26 @@ int transport_generic_do_tmr(struct se_cmd *cmd) int ret; switch (tmr->function) { - case ABORT_TASK: + case TMR_ABORT_TASK: ref_cmd = tmr->ref_cmd; tmr->response = TMR_FUNCTION_REJECTED; break; - case ABORT_TASK_SET: - case CLEAR_ACA: - case CLEAR_TASK_SET: + case TMR_ABORT_TASK_SET: + case TMR_CLEAR_ACA: + case TMR_CLEAR_TASK_SET: tmr->response = TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED; break; - case LUN_RESET: + case TMR_LUN_RESET: ret = core_tmr_lun_reset(dev, tmr, NULL, NULL); tmr->response = (!ret) ? TMR_FUNCTION_COMPLETE : TMR_FUNCTION_REJECTED; break; -#if 0 - case TARGET_WARM_RESET: - transport_generic_host_reset(dev->se_hba); + case TMR_TARGET_WARM_RESET: tmr->response = TMR_FUNCTION_REJECTED; break; - case TARGET_COLD_RESET: - transport_generic_host_reset(dev->se_hba); - transport_generic_cold_reset(dev->se_hba); + case TMR_TARGET_COLD_RESET: tmr->response = TMR_FUNCTION_REJECTED; break; -#endif default: printk(KERN_ERR "Uknown TMR function: 0x%02x.\n", tmr->function); diff --git a/include/target/target_core_tmr.h b/include/target/target_core_tmr.h index 6c8248bc2c66..bd5596807478 100644 --- a/include/target/target_core_tmr.h +++ b/include/target/target_core_tmr.h @@ -1,37 +1,29 @@ #ifndef TARGET_CORE_TMR_H #define TARGET_CORE_TMR_H -/* task management function values */ -#ifdef ABORT_TASK -#undef ABORT_TASK -#endif /* ABORT_TASK */ -#define ABORT_TASK 1 -#ifdef ABORT_TASK_SET -#undef ABORT_TASK_SET -#endif /* ABORT_TASK_SET */ -#define ABORT_TASK_SET 2 -#ifdef CLEAR_ACA -#undef CLEAR_ACA -#endif /* CLEAR_ACA */ -#define CLEAR_ACA 3 -#ifdef CLEAR_TASK_SET -#undef CLEAR_TASK_SET -#endif /* CLEAR_TASK_SET */ -#define CLEAR_TASK_SET 4 -#define LUN_RESET 5 -#define TARGET_WARM_RESET 6 -#define TARGET_COLD_RESET 7 -#define TASK_REASSIGN 8 +/* fabric independent task management function values */ +enum tcm_tmreq_table { + TMR_ABORT_TASK = 1, + TMR_ABORT_TASK_SET = 2, + TMR_CLEAR_ACA = 3, + TMR_CLEAR_TASK_SET = 4, + TMR_LUN_RESET = 5, + TMR_TARGET_WARM_RESET = 6, + TMR_TARGET_COLD_RESET = 7, + TMR_FABRIC_TMR = 255, +}; -/* task management response values */ -#define TMR_FUNCTION_COMPLETE 0 -#define TMR_TASK_DOES_NOT_EXIST 1 -#define TMR_LUN_DOES_NOT_EXIST 2 -#define TMR_TASK_STILL_ALLEGIANT 3 -#define TMR_TASK_FAILOVER_NOT_SUPPORTED 4 -#define TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED 5 -#define TMR_FUNCTION_AUTHORIZATION_FAILED 6 -#define TMR_FUNCTION_REJECTED 255 +/* fabric independent task management response values */ +enum tcm_tmrsp_table { + TMR_FUNCTION_COMPLETE = 0, + TMR_TASK_DOES_NOT_EXIST = 1, + TMR_LUN_DOES_NOT_EXIST = 2, + TMR_TASK_STILL_ALLEGIANT = 3, + TMR_TASK_FAILOVER_NOT_SUPPORTED = 4, + TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED = 5, + TMR_FUNCTION_AUTHORIZATION_FAILED = 6, + TMR_FUNCTION_REJECTED = 255, +}; extern struct kmem_cache *se_tmr_req_cache; -- cgit v1.2.3 From 15fb48cc40be170423fe8ddd17666aa6175315e3 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:06:10 -0700 Subject: [SCSI] target: update version to v4.0.0-rc7-ml Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- include/target/target_core_base.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include') diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index b3a62e451313..79f2e0a30dc8 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -9,7 +9,7 @@ #include #include -#define TARGET_CORE_MOD_VERSION "v4.0.0-rc6" +#define TARGET_CORE_MOD_VERSION "v4.0.0-rc7-ml" #define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGABRT)) /* Used by transport_generic_allocate_iovecs() */ -- cgit v1.2.3 From 12d233842987d9972957419e427987b94f7bd7b4 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Mon, 14 Mar 2011 04:06:11 -0700 Subject: [SCSI] target: add initial statistics This patch adds a target_core_mib.c statistics conversion for backend context struct se_subsystem_dev + struct se_device config_group based statistics in target_core_device.c using CONFIGFS_EATTR() based struct config_item_types from target_core_stat.c code. The conversion from backend /proc/scsi_target/mib/ context output to configfs default groups+attributes include scsi_dev, scsi_lu, and scsi_tgt_dev output from within individual: /sys/kernel/config/target/core/$HBA/DEV/ The legacy procfs output now appear as individual configfs attributes under: *) $HBA/$DEV/statistics/scsi_dev: |-- indx |-- inst |-- ports `-- role *) $HBA/$DEV/statistics/scsi_lu: |-- creation_time |-- dev |-- dev_type |-- full_stat |-- hs_num_cmds |-- indx |-- inst |-- lu_name |-- lun |-- num_cmds |-- prod |-- read_mbytes |-- resets |-- rev |-- state_bit |-- status |-- vend `-- write_mbytes *) $HBA/$DEV/statistics/scsi_tgt_dev: |-- indx |-- inst |-- non_access_lus |-- num_lus |-- resets `-- status The conversion from backend /proc/scsi_target/mib/ context output to configfs default groups+attributes include scsi_port, scsi_tgt_port and scsi_transport output from within individual: /sys/kernel/config/target/fabric/$WWN/tpgt_$TPGT/lun/lun_$LUN_ID/statistics/ The legacy procfs output now appear as individual configfs attributes under: *) fabric/$WWN/tpgt_$TPGT/lun/lun_$LUN_ID/statistics/scsi_port |-- busy_count |-- dev |-- indx |-- inst `-- role *) fabric/$WWN/tpgt_$TPGT/lun/lun_$LUN_ID/statistics/scsi_tgt_port |-- dev |-- hs_in_cmds |-- in_cmds |-- indx |-- inst |-- name |-- port_index |-- read_mbytes `-- write_mbytes *) fabric/$WWN/tpgt_$TPGT/lun/lun_$LUN_ID/statistics/scsi_transport |-- dev_name |-- device |-- indx `-- inst The conversion from backend /proc/scsi_target/mib/ context output to configfs default groups+attributes include scsi_att_intr_port and scsi_auth_intr output from within individual: /sys/kernel/config/target/fabric/$WWN/tpgt_$TPGT/acls/$INITIATOR_WWN/lun_$LUN_ID/statistics/ The legacy procfs output now appear as individual configfs attributes under: *) acls/$INITIATOR_WWN/lun_$LUN_ID/statistics/scsi_att_intr_port |-- dev |-- indx |-- inst |-- port |-- port_auth_indx `-- port_ident *) acls/$INITIATOR_WWN/lun_$LUN_ID/statistics/scsi_auth_intr |-- att_count |-- creation_time |-- dev |-- dev_or_port |-- hs_num_cmds |-- indx |-- inst |-- intr_name |-- map_indx |-- num_cmds |-- port |-- read_mbytes |-- row_status `-- write_mbytes Also, this includes adding struct target_fabric_configfs_template-> tfc_wwn_fabric_stats_cit and ->tfc_tpg_nacl_stat_cit respectively for use during target_core_fabric_configfs.c:target_fabric_setup_cits() Signed-off-by: Nicholas A. Bellinger Signed-off-by: James Bottomley --- drivers/target/Makefile | 3 +- drivers/target/target_core_configfs.c | 76 +- drivers/target/target_core_fabric_configfs.c | 209 ++- drivers/target/target_core_stat.c | 1810 ++++++++++++++++++++++++++ drivers/target/target_core_stat.h | 8 + include/target/target_core_base.h | 35 +- include/target/target_core_configfs.h | 4 + 7 files changed, 2127 insertions(+), 18 deletions(-) create mode 100644 drivers/target/target_core_stat.c create mode 100644 drivers/target/target_core_stat.h (limited to 'include') diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 050ee6569b2b..4f3cb788f06a 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile @@ -12,7 +12,8 @@ target_core_mod-y := target_core_configfs.o \ target_core_transport.o \ target_core_cdb.o \ target_core_ua.o \ - target_core_rd.o + target_core_rd.o \ + target_core_stat.o obj-$(CONFIG_TARGET_CORE) += target_core_mod.o diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index a38fec4acceb..a5f44a6e6e1d 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -3,8 +3,8 @@ * * This file contains ConfigFS logic for the Generic Target Engine project. * - * Copyright (c) 2008-2010 Rising Tide Systems - * Copyright (c) 2008-2010 Linux-iSCSI.org + * Copyright (c) 2008-2011 Rising Tide Systems + * Copyright (c) 2008-2011 Linux-iSCSI.org * * Nicholas A. Bellinger * @@ -50,6 +50,7 @@ #include "target_core_hba.h" #include "target_core_pr.h" #include "target_core_rd.h" +#include "target_core_stat.h" static struct list_head g_tf_list; static struct mutex g_tf_lock; @@ -2709,6 +2710,34 @@ static struct config_item_type target_core_alua_cit = { /* End functions for struct config_item_type target_core_alua_cit */ +/* Start functions for struct config_item_type target_core_stat_cit */ + +static struct config_group *target_core_stat_mkdir( + struct config_group *group, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static void target_core_stat_rmdir( + struct config_group *group, + struct config_item *item) +{ + return; +} + +static struct configfs_group_operations target_core_stat_group_ops = { + .make_group = &target_core_stat_mkdir, + .drop_item = &target_core_stat_rmdir, +}; + +static struct config_item_type target_core_stat_cit = { + .ct_group_ops = &target_core_stat_group_ops, + .ct_owner = THIS_MODULE, +}; + +/* End functions for struct config_item_type target_core_stat_cit */ + /* Start functions for struct config_item_type target_core_hba_cit */ static struct config_group *target_core_make_subdev( @@ -2721,10 +2750,12 @@ static struct config_group *target_core_make_subdev( struct config_item *hba_ci = &group->cg_item; struct se_hba *hba = item_to_hba(hba_ci); struct config_group *dev_cg = NULL, *tg_pt_gp_cg = NULL; + struct config_group *dev_stat_grp = NULL; + int errno = -ENOMEM, ret; - if (mutex_lock_interruptible(&hba->hba_access_mutex)) - return NULL; - + ret = mutex_lock_interruptible(&hba->hba_access_mutex); + if (ret) + return ERR_PTR(ret); /* * Locate the struct se_subsystem_api from parent's struct se_hba. */ @@ -2754,7 +2785,7 @@ static struct config_group *target_core_make_subdev( se_dev->se_dev_hba = hba; dev_cg = &se_dev->se_dev_group; - dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 6, + dev_cg->default_groups = kzalloc(sizeof(struct config_group) * 7, GFP_KERNEL); if (!(dev_cg->default_groups)) goto out; @@ -2786,13 +2817,17 @@ static struct config_group *target_core_make_subdev( &target_core_dev_wwn_cit); config_group_init_type_name(&se_dev->t10_alua.alua_tg_pt_gps_group, "alua", &target_core_alua_tg_pt_gps_cit); + config_group_init_type_name(&se_dev->dev_stat_grps.stat_group, + "statistics", &target_core_stat_cit); + dev_cg->default_groups[0] = &se_dev->se_dev_attrib.da_group; dev_cg->default_groups[1] = &se_dev->se_dev_pr_group; dev_cg->default_groups[2] = &se_dev->t10_wwn.t10_wwn_group; dev_cg->default_groups[3] = &se_dev->t10_alua.alua_tg_pt_gps_group; - dev_cg->default_groups[4] = NULL; + dev_cg->default_groups[4] = &se_dev->dev_stat_grps.stat_group; + dev_cg->default_groups[5] = NULL; /* - * Add core/$HBA/$DEV/alua/tg_pt_gps/default_tg_pt_gp + * Add core/$HBA/$DEV/alua/default_tg_pt_gp */ tg_pt_gp = core_alua_allocate_tg_pt_gp(se_dev, "default_tg_pt_gp", 1); if (!(tg_pt_gp)) @@ -2812,6 +2847,17 @@ static struct config_group *target_core_make_subdev( tg_pt_gp_cg->default_groups[0] = &tg_pt_gp->tg_pt_gp_group; tg_pt_gp_cg->default_groups[1] = NULL; T10_ALUA(se_dev)->default_tg_pt_gp = tg_pt_gp; + /* + * Add core/$HBA/$DEV/statistics/ default groups + */ + dev_stat_grp = &DEV_STAT_GRP(se_dev)->stat_group; + dev_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 4, + GFP_KERNEL); + if (!dev_stat_grp->default_groups) { + printk(KERN_ERR "Unable to allocate dev_stat_grp->default_groups\n"); + goto out; + } + target_stat_setup_dev_default_groups(se_dev); printk(KERN_INFO "Target_Core_ConfigFS: Allocated struct se_subsystem_dev:" " %p se_dev_su_ptr: %p\n", se_dev, se_dev->se_dev_su_ptr); @@ -2823,6 +2869,8 @@ out: core_alua_free_tg_pt_gp(T10_ALUA(se_dev)->default_tg_pt_gp); T10_ALUA(se_dev)->default_tg_pt_gp = NULL; } + if (dev_stat_grp) + kfree(dev_stat_grp->default_groups); if (tg_pt_gp_cg) kfree(tg_pt_gp_cg->default_groups); if (dev_cg) @@ -2832,7 +2880,7 @@ out: kfree(se_dev); unlock: mutex_unlock(&hba->hba_access_mutex); - return NULL; + return ERR_PTR(errno); } static void target_core_drop_subdev( @@ -2844,7 +2892,7 @@ static void target_core_drop_subdev( struct se_hba *hba; struct se_subsystem_api *t; struct config_item *df_item; - struct config_group *dev_cg, *tg_pt_gp_cg; + struct config_group *dev_cg, *tg_pt_gp_cg, *dev_stat_grp; int i; hba = item_to_hba(&se_dev->se_dev_hba->hba_group.cg_item); @@ -2856,6 +2904,14 @@ static void target_core_drop_subdev( list_del(&se_dev->g_se_dev_list); spin_unlock(&se_global->g_device_lock); + dev_stat_grp = &DEV_STAT_GRP(se_dev)->stat_group; + for (i = 0; dev_stat_grp->default_groups[i]; i++) { + df_item = &dev_stat_grp->default_groups[i]->cg_item; + dev_stat_grp->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(dev_stat_grp->default_groups); + tg_pt_gp_cg = &T10_ALUA(se_dev)->alua_tg_pt_gps_group; for (i = 0; tg_pt_gp_cg->default_groups[i]; i++) { df_item = &tg_pt_gp_cg->default_groups[i]->cg_item; diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index b65d1c8e7740..07ab5a3bb8e8 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c @@ -4,10 +4,10 @@ * This file contains generic fabric module configfs infrastructure for * TCM v4.x code * - * Copyright (c) 2010 Rising Tide Systems - * Copyright (c) 2010 Linux-iSCSI.org + * Copyright (c) 2010,2011 Rising Tide Systems + * Copyright (c) 2010,2011 Linux-iSCSI.org * - * Copyright (c) 2010 Nicholas A. Bellinger + * Copyright (c) Nicholas A. Bellinger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -48,6 +48,7 @@ #include "target_core_alua.h" #include "target_core_hba.h" #include "target_core_pr.h" +#include "target_core_stat.h" #define TF_CIT_SETUP(_name, _item_ops, _group_ops, _attrs) \ static void target_fabric_setup_##_name##_cit(struct target_fabric_configfs *tf) \ @@ -241,6 +242,32 @@ TF_CIT_SETUP(tpg_mappedlun, &target_fabric_mappedlun_item_ops, NULL, /* End of tfc_tpg_mappedlun_cit */ +/* Start of tfc_tpg_mappedlun_port_cit */ + +static struct config_group *target_core_mappedlun_stat_mkdir( + struct config_group *group, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static void target_core_mappedlun_stat_rmdir( + struct config_group *group, + struct config_item *item) +{ + return; +} + +static struct configfs_group_operations target_fabric_mappedlun_stat_group_ops = { + .make_group = target_core_mappedlun_stat_mkdir, + .drop_item = target_core_mappedlun_stat_rmdir, +}; + +TF_CIT_SETUP(tpg_mappedlun_stat, NULL, &target_fabric_mappedlun_stat_group_ops, + NULL); + +/* End of tfc_tpg_mappedlun_port_cit */ + /* Start of tfc_tpg_nacl_attrib_cit */ CONFIGFS_EATTR_OPS(target_fabric_nacl_attrib, se_node_acl, acl_attrib_group); @@ -294,6 +321,7 @@ static struct config_group *target_fabric_make_mappedlun( struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; struct se_lun_acl *lacl; struct config_item *acl_ci; + struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; char *buf; unsigned long mapped_lun; int ret = 0; @@ -330,15 +358,42 @@ static struct config_group *target_fabric_make_mappedlun( lacl = core_dev_init_initiator_node_lun_acl(se_tpg, mapped_lun, config_item_name(acl_ci), &ret); - if (!(lacl)) + if (!(lacl)) { + ret = -EINVAL; goto out; + } + + lacl_cg = &lacl->se_lun_group; + lacl_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!lacl_cg->default_groups) { + printk(KERN_ERR "Unable to allocate lacl_cg->default_groups\n"); + ret = -ENOMEM; + goto out; + } config_group_init_type_name(&lacl->se_lun_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_cit); + config_group_init_type_name(&lacl->ml_stat_grps.stat_group, + "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_mappedlun_stat_cit); + lacl_cg->default_groups[0] = &lacl->ml_stat_grps.stat_group; + lacl_cg->default_groups[1] = NULL; + + ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; + ml_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, + GFP_KERNEL); + if (!ml_stat_grp->default_groups) { + printk(KERN_ERR "Unable to allocate ml_stat_grp->default_groups\n"); + ret = -ENOMEM; + goto out; + } + target_stat_setup_mappedlun_default_groups(lacl); kfree(buf); return &lacl->se_lun_group; out: + if (lacl_cg) + kfree(lacl_cg->default_groups); kfree(buf); return ERR_PTR(ret); } @@ -347,6 +402,28 @@ static void target_fabric_drop_mappedlun( struct config_group *group, struct config_item *item) { + struct se_lun_acl *lacl = container_of(to_config_group(item), + struct se_lun_acl, se_lun_group); + struct config_item *df_item; + struct config_group *lacl_cg = NULL, *ml_stat_grp = NULL; + int i; + + ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; + for (i = 0; ml_stat_grp->default_groups[i]; i++) { + df_item = &ml_stat_grp->default_groups[i]->cg_item; + ml_stat_grp->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(ml_stat_grp->default_groups); + + lacl_cg = &lacl->se_lun_group; + for (i = 0; lacl_cg->default_groups[i]; i++) { + df_item = &lacl_cg->default_groups[i]->cg_item; + lacl_cg->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(lacl_cg->default_groups); + config_item_put(item); } @@ -376,6 +453,15 @@ TF_CIT_SETUP(tpg_nacl_base, &target_fabric_nacl_base_item_ops, /* End of tfc_tpg_nacl_base_cit */ +/* Start of tfc_node_fabric_stats_cit */ +/* + * This is used as a placeholder for struct se_node_acl->acl_fabric_stat_group + * to allow fabrics access to ->acl_fabric_stat_group->default_groups[] + */ +TF_CIT_SETUP(tpg_nacl_stat, NULL, NULL, NULL); + +/* End of tfc_wwn_fabric_stats_cit */ + /* Start of tfc_tpg_nacl_cit */ static struct config_group *target_fabric_make_nodeacl( @@ -402,7 +488,8 @@ static struct config_group *target_fabric_make_nodeacl( nacl_cg->default_groups[0] = &se_nacl->acl_attrib_group; nacl_cg->default_groups[1] = &se_nacl->acl_auth_group; nacl_cg->default_groups[2] = &se_nacl->acl_param_group; - nacl_cg->default_groups[3] = NULL; + nacl_cg->default_groups[3] = &se_nacl->acl_fabric_stat_group; + nacl_cg->default_groups[4] = NULL; config_group_init_type_name(&se_nacl->acl_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_nacl_base_cit); @@ -412,6 +499,9 @@ static struct config_group *target_fabric_make_nodeacl( &TF_CIT_TMPL(tf)->tfc_tpg_nacl_auth_cit); config_group_init_type_name(&se_nacl->acl_param_group, "param", &TF_CIT_TMPL(tf)->tfc_tpg_nacl_param_cit); + config_group_init_type_name(&se_nacl->acl_fabric_stat_group, + "fabric_statistics", + &TF_CIT_TMPL(tf)->tfc_tpg_nacl_stat_cit); return &se_nacl->acl_group; } @@ -758,6 +848,31 @@ TF_CIT_SETUP(tpg_port, &target_fabric_port_item_ops, NULL, target_fabric_port_at /* End of tfc_tpg_port_cit */ +/* Start of tfc_tpg_port_stat_cit */ + +static struct config_group *target_core_port_stat_mkdir( + struct config_group *group, + const char *name) +{ + return ERR_PTR(-ENOSYS); +} + +static void target_core_port_stat_rmdir( + struct config_group *group, + struct config_item *item) +{ + return; +} + +static struct configfs_group_operations target_fabric_port_stat_group_ops = { + .make_group = target_core_port_stat_mkdir, + .drop_item = target_core_port_stat_rmdir, +}; + +TF_CIT_SETUP(tpg_port_stat, NULL, &target_fabric_port_stat_group_ops, NULL); + +/* End of tfc_tpg_port_stat_cit */ + /* Start of tfc_tpg_lun_cit */ static struct config_group *target_fabric_make_lun( @@ -768,7 +883,9 @@ static struct config_group *target_fabric_make_lun( struct se_portal_group *se_tpg = container_of(group, struct se_portal_group, tpg_lun_group); struct target_fabric_configfs *tf = se_tpg->se_tpg_wwn->wwn_tf; + struct config_group *lun_cg = NULL, *port_stat_grp = NULL; unsigned long unpacked_lun; + int errno; if (strstr(name, "lun_") != name) { printk(KERN_ERR "Unable to locate \'_\" in" @@ -782,16 +899,64 @@ static struct config_group *target_fabric_make_lun( if (!(lun)) return ERR_PTR(-EINVAL); + lun_cg = &lun->lun_group; + lun_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, + GFP_KERNEL); + if (!lun_cg->default_groups) { + printk(KERN_ERR "Unable to allocate lun_cg->default_groups\n"); + return ERR_PTR(-ENOMEM); + } + config_group_init_type_name(&lun->lun_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_port_cit); + config_group_init_type_name(&lun->port_stat_grps.stat_group, + "statistics", &TF_CIT_TMPL(tf)->tfc_tpg_port_stat_cit); + lun_cg->default_groups[0] = &lun->port_stat_grps.stat_group; + lun_cg->default_groups[1] = NULL; + + port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; + port_stat_grp->default_groups = kzalloc(sizeof(struct config_group) * 3, + GFP_KERNEL); + if (!port_stat_grp->default_groups) { + printk(KERN_ERR "Unable to allocate port_stat_grp->default_groups\n"); + errno = -ENOMEM; + goto out; + } + target_stat_setup_port_default_groups(lun); return &lun->lun_group; +out: + if (lun_cg) + kfree(lun_cg->default_groups); + return ERR_PTR(errno); } static void target_fabric_drop_lun( struct config_group *group, struct config_item *item) { + struct se_lun *lun = container_of(to_config_group(item), + struct se_lun, lun_group); + struct config_item *df_item; + struct config_group *lun_cg, *port_stat_grp; + int i; + + port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; + for (i = 0; port_stat_grp->default_groups[i]; i++) { + df_item = &port_stat_grp->default_groups[i]->cg_item; + port_stat_grp->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(port_stat_grp->default_groups); + + lun_cg = &lun->lun_group; + for (i = 0; lun_cg->default_groups[i]; i++) { + df_item = &lun_cg->default_groups[i]->cg_item; + lun_cg->default_groups[i] = NULL; + config_item_put(df_item); + } + kfree(lun_cg->default_groups); + config_item_put(item); } @@ -946,6 +1111,15 @@ TF_CIT_SETUP(tpg, &target_fabric_tpg_item_ops, &target_fabric_tpg_group_ops, /* End of tfc_tpg_cit */ +/* Start of tfc_wwn_fabric_stats_cit */ +/* + * This is used as a placeholder for struct se_wwn->fabric_stat_group + * to allow fabrics access to ->fabric_stat_group->default_groups[] + */ +TF_CIT_SETUP(wwn_fabric_stats, NULL, NULL, NULL); + +/* End of tfc_wwn_fabric_stats_cit */ + /* Start of tfc_wwn_cit */ static struct config_group *target_fabric_make_wwn( @@ -966,8 +1140,17 @@ static struct config_group *target_fabric_make_wwn( return ERR_PTR(-EINVAL); wwn->wwn_tf = tf; + /* + * Setup default groups from pre-allocated wwn->wwn_default_groups + */ + wwn->wwn_group.default_groups = wwn->wwn_default_groups; + wwn->wwn_group.default_groups[0] = &wwn->fabric_stat_group; + wwn->wwn_group.default_groups[1] = NULL; + config_group_init_type_name(&wwn->wwn_group, name, &TF_CIT_TMPL(tf)->tfc_tpg_cit); + config_group_init_type_name(&wwn->fabric_stat_group, "fabric_statistics", + &TF_CIT_TMPL(tf)->tfc_wwn_fabric_stats_cit); return &wwn->wwn_group; } @@ -976,6 +1159,18 @@ static void target_fabric_drop_wwn( struct config_group *group, struct config_item *item) { + struct se_wwn *wwn = container_of(to_config_group(item), + struct se_wwn, wwn_group); + struct config_item *df_item; + struct config_group *cg = &wwn->wwn_group; + int i; + + for (i = 0; cg->default_groups[i]; i++) { + df_item = &cg->default_groups[i]->cg_item; + cg->default_groups[i] = NULL; + config_item_put(df_item); + } + config_item_put(item); } @@ -1015,9 +1210,11 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf) { target_fabric_setup_discovery_cit(tf); target_fabric_setup_wwn_cit(tf); + target_fabric_setup_wwn_fabric_stats_cit(tf); target_fabric_setup_tpg_cit(tf); target_fabric_setup_tpg_base_cit(tf); target_fabric_setup_tpg_port_cit(tf); + target_fabric_setup_tpg_port_stat_cit(tf); target_fabric_setup_tpg_lun_cit(tf); target_fabric_setup_tpg_np_cit(tf); target_fabric_setup_tpg_np_base_cit(tf); @@ -1028,7 +1225,9 @@ int target_fabric_setup_cits(struct target_fabric_configfs *tf) target_fabric_setup_tpg_nacl_attrib_cit(tf); target_fabric_setup_tpg_nacl_auth_cit(tf); target_fabric_setup_tpg_nacl_param_cit(tf); + target_fabric_setup_tpg_nacl_stat_cit(tf); target_fabric_setup_tpg_mappedlun_cit(tf); + target_fabric_setup_tpg_mappedlun_stat_cit(tf); return 0; } diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c new file mode 100644 index 000000000000..5e3a067a7475 --- /dev/null +++ b/drivers/target/target_core_stat.c @@ -0,0 +1,1810 @@ +/******************************************************************************* + * Filename: target_core_stat.c + * + * Copyright (c) 2011 Rising Tide Systems + * Copyright (c) 2011 Linux-iSCSI.org + * + * Modern ConfigFS group context specific statistics based on original + * target_core_mib.c code + * + * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. + * + * Nicholas A. Bellinger + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + ******************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "target_core_hba.h" + +#ifndef INITIAL_JIFFIES +#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) +#endif + +#define NONE "None" +#define ISPRINT(a) ((a >= ' ') && (a <= '~')) + +#define SCSI_LU_INDEX 1 +#define LU_COUNT 1 + +/* + * SCSI Device Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_dev, se_dev_stat_grps); +#define DEV_STAT_SCSI_DEV_ATTR(_name, _mode) \ +static struct target_stat_scsi_dev_attribute \ + target_stat_scsi_dev_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_dev_show_attr_##_name, \ + target_stat_scsi_dev_store_attr_##_name); + +#define DEV_STAT_SCSI_DEV_ATTR_RO(_name) \ +static struct target_stat_scsi_dev_attribute \ + target_stat_scsi_dev_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_dev_show_attr_##_name); + +static ssize_t target_stat_scsi_dev_show_attr_inst( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_hba *hba = se_subdev->se_dev_hba; + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); +} +DEV_STAT_SCSI_DEV_ATTR_RO(inst); + +static ssize_t target_stat_scsi_dev_show_attr_indx( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); +} +DEV_STAT_SCSI_DEV_ATTR_RO(indx); + +static ssize_t target_stat_scsi_dev_show_attr_role( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "Target\n"); +} +DEV_STAT_SCSI_DEV_ATTR_RO(role); + +static ssize_t target_stat_scsi_dev_show_attr_ports( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_port_count); +} +DEV_STAT_SCSI_DEV_ATTR_RO(ports); + +CONFIGFS_EATTR_OPS(target_stat_scsi_dev, se_dev_stat_grps, scsi_dev_group); + +static struct configfs_attribute *target_stat_scsi_dev_attrs[] = { + &target_stat_scsi_dev_inst.attr, + &target_stat_scsi_dev_indx.attr, + &target_stat_scsi_dev_role.attr, + &target_stat_scsi_dev_ports.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_dev_attrib_ops = { + .show_attribute = target_stat_scsi_dev_attr_show, + .store_attribute = target_stat_scsi_dev_attr_store, +}; + +static struct config_item_type target_stat_scsi_dev_cit = { + .ct_item_ops = &target_stat_scsi_dev_attrib_ops, + .ct_attrs = target_stat_scsi_dev_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Target Device Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_dev, se_dev_stat_grps); +#define DEV_STAT_SCSI_TGT_DEV_ATTR(_name, _mode) \ +static struct target_stat_scsi_tgt_dev_attribute \ + target_stat_scsi_tgt_dev_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_tgt_dev_show_attr_##_name, \ + target_stat_scsi_tgt_dev_store_attr_##_name); + +#define DEV_STAT_SCSI_TGT_DEV_ATTR_RO(_name) \ +static struct target_stat_scsi_tgt_dev_attribute \ + target_stat_scsi_tgt_dev_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_tgt_dev_show_attr_##_name); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_inst( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_hba *hba = se_subdev->se_dev_hba; + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(inst); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_indx( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(indx); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_num_lus( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", LU_COUNT); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(num_lus); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_status( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + char status[16]; + + if (!dev) + return -ENODEV; + + switch (dev->dev_status) { + case TRANSPORT_DEVICE_ACTIVATED: + strcpy(status, "activated"); + break; + case TRANSPORT_DEVICE_DEACTIVATED: + strcpy(status, "deactivated"); + break; + case TRANSPORT_DEVICE_SHUTDOWN: + strcpy(status, "shutdown"); + break; + case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: + case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: + strcpy(status, "offline"); + break; + default: + sprintf(status, "unknown(%d)", dev->dev_status); + break; + } + + return snprintf(page, PAGE_SIZE, "%s\n", status); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(status); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_non_access_lus( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + int non_accessible_lus; + + if (!dev) + return -ENODEV; + + switch (dev->dev_status) { + case TRANSPORT_DEVICE_ACTIVATED: + non_accessible_lus = 0; + break; + case TRANSPORT_DEVICE_DEACTIVATED: + case TRANSPORT_DEVICE_SHUTDOWN: + case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: + case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: + default: + non_accessible_lus = 1; + break; + } + + return snprintf(page, PAGE_SIZE, "%u\n", non_accessible_lus); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(non_access_lus); + +static ssize_t target_stat_scsi_tgt_dev_show_attr_resets( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); +} +DEV_STAT_SCSI_TGT_DEV_ATTR_RO(resets); + + +CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_dev, se_dev_stat_grps, scsi_tgt_dev_group); + +static struct configfs_attribute *target_stat_scsi_tgt_dev_attrs[] = { + &target_stat_scsi_tgt_dev_inst.attr, + &target_stat_scsi_tgt_dev_indx.attr, + &target_stat_scsi_tgt_dev_num_lus.attr, + &target_stat_scsi_tgt_dev_status.attr, + &target_stat_scsi_tgt_dev_non_access_lus.attr, + &target_stat_scsi_tgt_dev_resets.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_tgt_dev_attrib_ops = { + .show_attribute = target_stat_scsi_tgt_dev_attr_show, + .store_attribute = target_stat_scsi_tgt_dev_attr_store, +}; + +static struct config_item_type target_stat_scsi_tgt_dev_cit = { + .ct_item_ops = &target_stat_scsi_tgt_dev_attrib_ops, + .ct_attrs = target_stat_scsi_tgt_dev_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Logical Unit Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_lu, se_dev_stat_grps); +#define DEV_STAT_SCSI_LU_ATTR(_name, _mode) \ +static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_lu_show_attr_##_name, \ + target_stat_scsi_lu_store_attr_##_name); + +#define DEV_STAT_SCSI_LU_ATTR_RO(_name) \ +static struct target_stat_scsi_lu_attribute target_stat_scsi_lu_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_lu_show_attr_##_name); + +static ssize_t target_stat_scsi_lu_show_attr_inst( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_hba *hba = se_subdev->se_dev_hba; + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); +} +DEV_STAT_SCSI_LU_ATTR_RO(inst); + +static ssize_t target_stat_scsi_lu_show_attr_dev( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); +} +DEV_STAT_SCSI_LU_ATTR_RO(dev); + +static ssize_t target_stat_scsi_lu_show_attr_indx( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + return snprintf(page, PAGE_SIZE, "%u\n", SCSI_LU_INDEX); +} +DEV_STAT_SCSI_LU_ATTR_RO(indx); + +static ssize_t target_stat_scsi_lu_show_attr_lun( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + /* FIXME: scsiLuDefaultLun */ + return snprintf(page, PAGE_SIZE, "%llu\n", (unsigned long long)0); +} +DEV_STAT_SCSI_LU_ATTR_RO(lun); + +static ssize_t target_stat_scsi_lu_show_attr_lu_name( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + /* scsiLuWwnName */ + return snprintf(page, PAGE_SIZE, "%s\n", + (strlen(DEV_T10_WWN(dev)->unit_serial)) ? + (char *)&DEV_T10_WWN(dev)->unit_serial[0] : "None"); +} +DEV_STAT_SCSI_LU_ATTR_RO(lu_name); + +static ssize_t target_stat_scsi_lu_show_attr_vend( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + int j; + char str[28]; + + if (!dev) + return -ENODEV; + /* scsiLuVendorId */ + memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); + for (j = 0; j < 8; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->vendor[j]) ? + DEV_T10_WWN(dev)->vendor[j] : 0x20; + str[8] = 0; + return snprintf(page, PAGE_SIZE, "%s\n", str); +} +DEV_STAT_SCSI_LU_ATTR_RO(vend); + +static ssize_t target_stat_scsi_lu_show_attr_prod( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + int j; + char str[28]; + + if (!dev) + return -ENODEV; + + /* scsiLuProductId */ + memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); + for (j = 0; j < 16; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->model[j]) ? + DEV_T10_WWN(dev)->model[j] : 0x20; + str[16] = 0; + return snprintf(page, PAGE_SIZE, "%s\n", str); +} +DEV_STAT_SCSI_LU_ATTR_RO(prod); + +static ssize_t target_stat_scsi_lu_show_attr_rev( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + int j; + char str[28]; + + if (!dev) + return -ENODEV; + + /* scsiLuRevisionId */ + memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); + for (j = 0; j < 4; j++) + str[j] = ISPRINT(DEV_T10_WWN(dev)->revision[j]) ? + DEV_T10_WWN(dev)->revision[j] : 0x20; + str[4] = 0; + return snprintf(page, PAGE_SIZE, "%s\n", str); +} +DEV_STAT_SCSI_LU_ATTR_RO(rev); + +static ssize_t target_stat_scsi_lu_show_attr_dev_type( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuPeripheralType */ + return snprintf(page, PAGE_SIZE, "%u\n", + TRANSPORT(dev)->get_device_type(dev)); +} +DEV_STAT_SCSI_LU_ATTR_RO(dev_type); + +static ssize_t target_stat_scsi_lu_show_attr_status( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuStatus */ + return snprintf(page, PAGE_SIZE, "%s\n", + (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? + "available" : "notavailable"); +} +DEV_STAT_SCSI_LU_ATTR_RO(status); + +static ssize_t target_stat_scsi_lu_show_attr_state_bit( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuState */ + return snprintf(page, PAGE_SIZE, "exposed\n"); +} +DEV_STAT_SCSI_LU_ATTR_RO(state_bit); + +static ssize_t target_stat_scsi_lu_show_attr_num_cmds( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuNumCommands */ + return snprintf(page, PAGE_SIZE, "%llu\n", + (unsigned long long)dev->num_cmds); +} +DEV_STAT_SCSI_LU_ATTR_RO(num_cmds); + +static ssize_t target_stat_scsi_lu_show_attr_read_mbytes( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuReadMegaBytes */ + return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->read_bytes >> 20)); +} +DEV_STAT_SCSI_LU_ATTR_RO(read_mbytes); + +static ssize_t target_stat_scsi_lu_show_attr_write_mbytes( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuWrittenMegaBytes */ + return snprintf(page, PAGE_SIZE, "%u\n", (u32)(dev->write_bytes >> 20)); +} +DEV_STAT_SCSI_LU_ATTR_RO(write_mbytes); + +static ssize_t target_stat_scsi_lu_show_attr_resets( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuInResets */ + return snprintf(page, PAGE_SIZE, "%u\n", dev->num_resets); +} +DEV_STAT_SCSI_LU_ATTR_RO(resets); + +static ssize_t target_stat_scsi_lu_show_attr_full_stat( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* FIXME: scsiLuOutTaskSetFullStatus */ + return snprintf(page, PAGE_SIZE, "%u\n", 0); +} +DEV_STAT_SCSI_LU_ATTR_RO(full_stat); + +static ssize_t target_stat_scsi_lu_show_attr_hs_num_cmds( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* FIXME: scsiLuHSInCommands */ + return snprintf(page, PAGE_SIZE, "%u\n", 0); +} +DEV_STAT_SCSI_LU_ATTR_RO(hs_num_cmds); + +static ssize_t target_stat_scsi_lu_show_attr_creation_time( + struct se_dev_stat_grps *sgrps, char *page) +{ + struct se_subsystem_dev *se_subdev = container_of(sgrps, + struct se_subsystem_dev, dev_stat_grps); + struct se_device *dev = se_subdev->se_dev_ptr; + + if (!dev) + return -ENODEV; + + /* scsiLuCreationTime */ + return snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)dev->creation_time - + INITIAL_JIFFIES) * 100 / HZ)); +} +DEV_STAT_SCSI_LU_ATTR_RO(creation_time); + +CONFIGFS_EATTR_OPS(target_stat_scsi_lu, se_dev_stat_grps, scsi_lu_group); + +static struct configfs_attribute *target_stat_scsi_lu_attrs[] = { + &target_stat_scsi_lu_inst.attr, + &target_stat_scsi_lu_dev.attr, + &target_stat_scsi_lu_indx.attr, + &target_stat_scsi_lu_lun.attr, + &target_stat_scsi_lu_lu_name.attr, + &target_stat_scsi_lu_vend.attr, + &target_stat_scsi_lu_prod.attr, + &target_stat_scsi_lu_rev.attr, + &target_stat_scsi_lu_dev_type.attr, + &target_stat_scsi_lu_status.attr, + &target_stat_scsi_lu_state_bit.attr, + &target_stat_scsi_lu_num_cmds.attr, + &target_stat_scsi_lu_read_mbytes.attr, + &target_stat_scsi_lu_write_mbytes.attr, + &target_stat_scsi_lu_resets.attr, + &target_stat_scsi_lu_full_stat.attr, + &target_stat_scsi_lu_hs_num_cmds.attr, + &target_stat_scsi_lu_creation_time.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_lu_attrib_ops = { + .show_attribute = target_stat_scsi_lu_attr_show, + .store_attribute = target_stat_scsi_lu_attr_store, +}; + +static struct config_item_type target_stat_scsi_lu_cit = { + .ct_item_ops = &target_stat_scsi_lu_attrib_ops, + .ct_attrs = target_stat_scsi_lu_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * Called from target_core_configfs.c:target_core_make_subdev() to setup + * the target statistics groups + configfs CITs located in target_core_stat.c + */ +void target_stat_setup_dev_default_groups(struct se_subsystem_dev *se_subdev) +{ + struct config_group *dev_stat_grp = &DEV_STAT_GRP(se_subdev)->stat_group; + + config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_dev_group, + "scsi_dev", &target_stat_scsi_dev_cit); + config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_tgt_dev_group, + "scsi_tgt_dev", &target_stat_scsi_tgt_dev_cit); + config_group_init_type_name(&DEV_STAT_GRP(se_subdev)->scsi_lu_group, + "scsi_lu", &target_stat_scsi_lu_cit); + + dev_stat_grp->default_groups[0] = &DEV_STAT_GRP(se_subdev)->scsi_dev_group; + dev_stat_grp->default_groups[1] = &DEV_STAT_GRP(se_subdev)->scsi_tgt_dev_group; + dev_stat_grp->default_groups[2] = &DEV_STAT_GRP(se_subdev)->scsi_lu_group; + dev_stat_grp->default_groups[3] = NULL; +} + +/* + * SCSI Port Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_port, se_port_stat_grps); +#define DEV_STAT_SCSI_PORT_ATTR(_name, _mode) \ +static struct target_stat_scsi_port_attribute \ + target_stat_scsi_port_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_port_show_attr_##_name, \ + target_stat_scsi_port_store_attr_##_name); + +#define DEV_STAT_SCSI_PORT_ATTR_RO(_name) \ +static struct target_stat_scsi_port_attribute \ + target_stat_scsi_port_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_port_show_attr_##_name); + +static ssize_t target_stat_scsi_port_show_attr_inst( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_device *dev = lun->lun_se_dev; + struct se_hba *hba; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + hba = dev->se_hba; + ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(inst); + +static ssize_t target_stat_scsi_port_show_attr_dev( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_device *dev = lun->lun_se_dev; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(dev); + +static ssize_t target_stat_scsi_port_show_attr_indx( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(indx); + +static ssize_t target_stat_scsi_port_show_attr_role( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + ssize_t ret; + + if (!dev) + return -ENODEV; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%s%u\n", "Device", dev->dev_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(role); + +static ssize_t target_stat_scsi_port_show_attr_busy_count( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + /* FIXME: scsiPortBusyStatuses */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_PORT_ATTR_RO(busy_count); + +CONFIGFS_EATTR_OPS(target_stat_scsi_port, se_port_stat_grps, scsi_port_group); + +static struct configfs_attribute *target_stat_scsi_port_attrs[] = { + &target_stat_scsi_port_inst.attr, + &target_stat_scsi_port_dev.attr, + &target_stat_scsi_port_indx.attr, + &target_stat_scsi_port_role.attr, + &target_stat_scsi_port_busy_count.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_port_attrib_ops = { + .show_attribute = target_stat_scsi_port_attr_show, + .store_attribute = target_stat_scsi_port_attr_store, +}; + +static struct config_item_type target_stat_scsi_port_cit = { + .ct_item_ops = &target_stat_scsi_port_attrib_ops, + .ct_attrs = target_stat_scsi_port_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Target Port Table + */ +CONFIGFS_EATTR_STRUCT(target_stat_scsi_tgt_port, se_port_stat_grps); +#define DEV_STAT_SCSI_TGT_PORT_ATTR(_name, _mode) \ +static struct target_stat_scsi_tgt_port_attribute \ + target_stat_scsi_tgt_port_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_tgt_port_show_attr_##_name, \ + target_stat_scsi_tgt_port_store_attr_##_name); + +#define DEV_STAT_SCSI_TGT_PORT_ATTR_RO(_name) \ +static struct target_stat_scsi_tgt_port_attribute \ + target_stat_scsi_tgt_port_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_tgt_port_show_attr_##_name); + +static ssize_t target_stat_scsi_tgt_port_show_attr_inst( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + struct se_hba *hba; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + hba = dev->se_hba; + ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(inst); + +static ssize_t target_stat_scsi_tgt_port_show_attr_dev( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%u\n", dev->dev_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(dev); + +static ssize_t target_stat_scsi_tgt_port_show_attr_indx( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + ret = snprintf(page, PAGE_SIZE, "%u\n", sep->sep_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(indx); + +static ssize_t target_stat_scsi_tgt_port_show_attr_name( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%sPort#%u\n", + TPG_TFO(tpg)->get_fabric_name(), sep->sep_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(name); + +static ssize_t target_stat_scsi_tgt_port_show_attr_port_index( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%s%s%d\n", + TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+", + TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(port_index); + +static ssize_t target_stat_scsi_tgt_port_show_attr_in_cmds( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%llu\n", sep->sep_stats.cmd_pdus); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(in_cmds); + +static ssize_t target_stat_scsi_tgt_port_show_attr_write_mbytes( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(sep->sep_stats.rx_data_octets >> 20)); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(write_mbytes); + +static ssize_t target_stat_scsi_tgt_port_show_attr_read_mbytes( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + ret = snprintf(page, PAGE_SIZE, "%u\n", + (u32)(sep->sep_stats.tx_data_octets >> 20)); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(read_mbytes); + +static ssize_t target_stat_scsi_tgt_port_show_attr_hs_in_cmds( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + + /* FIXME: scsiTgtPortHsInCommands */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TGT_PORT_ATTR_RO(hs_in_cmds); + +CONFIGFS_EATTR_OPS(target_stat_scsi_tgt_port, se_port_stat_grps, + scsi_tgt_port_group); + +static struct configfs_attribute *target_stat_scsi_tgt_port_attrs[] = { + &target_stat_scsi_tgt_port_inst.attr, + &target_stat_scsi_tgt_port_dev.attr, + &target_stat_scsi_tgt_port_indx.attr, + &target_stat_scsi_tgt_port_name.attr, + &target_stat_scsi_tgt_port_port_index.attr, + &target_stat_scsi_tgt_port_in_cmds.attr, + &target_stat_scsi_tgt_port_write_mbytes.attr, + &target_stat_scsi_tgt_port_read_mbytes.attr, + &target_stat_scsi_tgt_port_hs_in_cmds.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_tgt_port_attrib_ops = { + .show_attribute = target_stat_scsi_tgt_port_attr_show, + .store_attribute = target_stat_scsi_tgt_port_attr_store, +}; + +static struct config_item_type target_stat_scsi_tgt_port_cit = { + .ct_item_ops = &target_stat_scsi_tgt_port_attrib_ops, + .ct_attrs = target_stat_scsi_tgt_port_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Transport Table +o */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_transport, se_port_stat_grps); +#define DEV_STAT_SCSI_TRANSPORT_ATTR(_name, _mode) \ +static struct target_stat_scsi_transport_attribute \ + target_stat_scsi_transport_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_transport_show_attr_##_name, \ + target_stat_scsi_transport_store_attr_##_name); + +#define DEV_STAT_SCSI_TRANSPORT_ATTR_RO(_name) \ +static struct target_stat_scsi_transport_attribute \ + target_stat_scsi_transport_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_transport_show_attr_##_name); + +static ssize_t target_stat_scsi_transport_show_attr_inst( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + struct se_hba *hba; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + + hba = dev->se_hba; + ret = snprintf(page, PAGE_SIZE, "%u\n", hba->hba_index); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TRANSPORT_ATTR_RO(inst); + +static ssize_t target_stat_scsi_transport_show_attr_device( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + /* scsiTransportType */ + ret = snprintf(page, PAGE_SIZE, "scsiTransport%s\n", + TPG_TFO(tpg)->get_fabric_name()); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TRANSPORT_ATTR_RO(device); + +static ssize_t target_stat_scsi_transport_show_attr_indx( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_port *sep; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + ret = snprintf(page, PAGE_SIZE, "%u\n", + TPG_TFO(tpg)->tpg_get_inst_index(tpg)); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TRANSPORT_ATTR_RO(indx); + +static ssize_t target_stat_scsi_transport_show_attr_dev_name( + struct se_port_stat_grps *pgrps, char *page) +{ + struct se_lun *lun = container_of(pgrps, struct se_lun, port_stat_grps); + struct se_device *dev = lun->lun_se_dev; + struct se_port *sep; + struct se_portal_group *tpg; + struct t10_wwn *wwn; + ssize_t ret; + + spin_lock(&lun->lun_sep_lock); + sep = lun->lun_sep; + if (!sep) { + spin_unlock(&lun->lun_sep_lock); + return -ENODEV; + } + tpg = sep->sep_tpg; + wwn = DEV_T10_WWN(dev); + /* scsiTransportDevName */ + ret = snprintf(page, PAGE_SIZE, "%s+%s\n", + TPG_TFO(tpg)->tpg_get_wwn(tpg), + (strlen(wwn->unit_serial)) ? wwn->unit_serial : + wwn->vendor); + spin_unlock(&lun->lun_sep_lock); + return ret; +} +DEV_STAT_SCSI_TRANSPORT_ATTR_RO(dev_name); + +CONFIGFS_EATTR_OPS(target_stat_scsi_transport, se_port_stat_grps, + scsi_transport_group); + +static struct configfs_attribute *target_stat_scsi_transport_attrs[] = { + &target_stat_scsi_transport_inst.attr, + &target_stat_scsi_transport_device.attr, + &target_stat_scsi_transport_indx.attr, + &target_stat_scsi_transport_dev_name.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_transport_attrib_ops = { + .show_attribute = target_stat_scsi_transport_attr_show, + .store_attribute = target_stat_scsi_transport_attr_store, +}; + +static struct config_item_type target_stat_scsi_transport_cit = { + .ct_item_ops = &target_stat_scsi_transport_attrib_ops, + .ct_attrs = target_stat_scsi_transport_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * Called from target_core_fabric_configfs.c:target_fabric_make_lun() to setup + * the target port statistics groups + configfs CITs located in target_core_stat.c + */ +void target_stat_setup_port_default_groups(struct se_lun *lun) +{ + struct config_group *port_stat_grp = &PORT_STAT_GRP(lun)->stat_group; + + config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_port_group, + "scsi_port", &target_stat_scsi_port_cit); + config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_tgt_port_group, + "scsi_tgt_port", &target_stat_scsi_tgt_port_cit); + config_group_init_type_name(&PORT_STAT_GRP(lun)->scsi_transport_group, + "scsi_transport", &target_stat_scsi_transport_cit); + + port_stat_grp->default_groups[0] = &PORT_STAT_GRP(lun)->scsi_port_group; + port_stat_grp->default_groups[1] = &PORT_STAT_GRP(lun)->scsi_tgt_port_group; + port_stat_grp->default_groups[2] = &PORT_STAT_GRP(lun)->scsi_transport_group; + port_stat_grp->default_groups[3] = NULL; +} + +/* + * SCSI Authorized Initiator Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_auth_intr, se_ml_stat_grps); +#define DEV_STAT_SCSI_AUTH_INTR_ATTR(_name, _mode) \ +static struct target_stat_scsi_auth_intr_attribute \ + target_stat_scsi_auth_intr_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_auth_intr_show_attr_##_name, \ + target_stat_scsi_auth_intr_store_attr_##_name); + +#define DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(_name) \ +static struct target_stat_scsi_auth_intr_attribute \ + target_stat_scsi_auth_intr_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_auth_intr_show_attr_##_name); + +static ssize_t target_stat_scsi_auth_intr_show_attr_inst( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + /* scsiInstIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", + TPG_TFO(tpg)->tpg_get_inst_index(tpg)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(inst); + +static ssize_t target_stat_scsi_auth_intr_show_attr_dev( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_lun *lun; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + lun = deve->se_lun; + /* scsiDeviceIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev); + +static ssize_t target_stat_scsi_auth_intr_show_attr_port( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + /* scsiAuthIntrTgtPortIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(port); + +static ssize_t target_stat_scsi_auth_intr_show_attr_indx( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(indx); + +static ssize_t target_stat_scsi_auth_intr_show_attr_dev_or_port( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrDevOrPort */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 1); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(dev_or_port); + +static ssize_t target_stat_scsi_auth_intr_show_attr_intr_name( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrName */ + ret = snprintf(page, PAGE_SIZE, "%s\n", nacl->initiatorname); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(intr_name); + +static ssize_t target_stat_scsi_auth_intr_show_attr_map_indx( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* FIXME: scsiAuthIntrLunMapIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(map_indx); + +static ssize_t target_stat_scsi_auth_intr_show_attr_att_count( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrAttachedTimes */ + ret = snprintf(page, PAGE_SIZE, "%u\n", deve->attach_count); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(att_count); + +static ssize_t target_stat_scsi_auth_intr_show_attr_num_cmds( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrOutCommands */ + ret = snprintf(page, PAGE_SIZE, "%u\n", deve->total_cmds); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(num_cmds); + +static ssize_t target_stat_scsi_auth_intr_show_attr_read_mbytes( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrReadMegaBytes */ + ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->read_bytes >> 20)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(read_mbytes); + +static ssize_t target_stat_scsi_auth_intr_show_attr_write_mbytes( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrWrittenMegaBytes */ + ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(deve->write_bytes >> 20)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(write_mbytes); + +static ssize_t target_stat_scsi_auth_intr_show_attr_hs_num_cmds( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* FIXME: scsiAuthIntrHSOutCommands */ + ret = snprintf(page, PAGE_SIZE, "%u\n", 0); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(hs_num_cmds); + +static ssize_t target_stat_scsi_auth_intr_show_attr_creation_time( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAuthIntrLastCreation */ + ret = snprintf(page, PAGE_SIZE, "%u\n", (u32)(((u32)deve->creation_time - + INITIAL_JIFFIES) * 100 / HZ)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(creation_time); + +static ssize_t target_stat_scsi_auth_intr_show_attr_row_status( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* FIXME: scsiAuthIntrRowStatus */ + ret = snprintf(page, PAGE_SIZE, "Ready\n"); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_AUTH_INTR_ATTR_RO(row_status); + +CONFIGFS_EATTR_OPS(target_stat_scsi_auth_intr, se_ml_stat_grps, + scsi_auth_intr_group); + +static struct configfs_attribute *target_stat_scsi_auth_intr_attrs[] = { + &target_stat_scsi_auth_intr_inst.attr, + &target_stat_scsi_auth_intr_dev.attr, + &target_stat_scsi_auth_intr_port.attr, + &target_stat_scsi_auth_intr_indx.attr, + &target_stat_scsi_auth_intr_dev_or_port.attr, + &target_stat_scsi_auth_intr_intr_name.attr, + &target_stat_scsi_auth_intr_map_indx.attr, + &target_stat_scsi_auth_intr_att_count.attr, + &target_stat_scsi_auth_intr_num_cmds.attr, + &target_stat_scsi_auth_intr_read_mbytes.attr, + &target_stat_scsi_auth_intr_write_mbytes.attr, + &target_stat_scsi_auth_intr_hs_num_cmds.attr, + &target_stat_scsi_auth_intr_creation_time.attr, + &target_stat_scsi_auth_intr_row_status.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_auth_intr_attrib_ops = { + .show_attribute = target_stat_scsi_auth_intr_attr_show, + .store_attribute = target_stat_scsi_auth_intr_attr_store, +}; + +static struct config_item_type target_stat_scsi_auth_intr_cit = { + .ct_item_ops = &target_stat_scsi_auth_intr_attrib_ops, + .ct_attrs = target_stat_scsi_auth_intr_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * SCSI Attached Initiator Port Table + */ + +CONFIGFS_EATTR_STRUCT(target_stat_scsi_att_intr_port, se_ml_stat_grps); +#define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR(_name, _mode) \ +static struct target_stat_scsi_att_intr_port_attribute \ + target_stat_scsi_att_intr_port_##_name = \ + __CONFIGFS_EATTR(_name, _mode, \ + target_stat_scsi_att_intr_port_show_attr_##_name, \ + target_stat_scsi_att_intr_port_store_attr_##_name); + +#define DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(_name) \ +static struct target_stat_scsi_att_intr_port_attribute \ + target_stat_scsi_att_intr_port_##_name = \ + __CONFIGFS_EATTR_RO(_name, \ + target_stat_scsi_att_intr_port_show_attr_##_name); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_inst( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + /* scsiInstIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", + TPG_TFO(tpg)->tpg_get_inst_index(tpg)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(inst); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_dev( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_lun *lun; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + lun = deve->se_lun; + /* scsiDeviceIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", lun->lun_se_dev->dev_index); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(dev); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_port( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + tpg = nacl->se_tpg; + /* scsiPortIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", TPG_TFO(tpg)->tpg_get_tag(tpg)); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_indx( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_session *se_sess; + struct se_portal_group *tpg; + ssize_t ret; + + spin_lock_irq(&nacl->nacl_sess_lock); + se_sess = nacl->nacl_sess; + if (!se_sess) { + spin_unlock_irq(&nacl->nacl_sess_lock); + return -ENODEV; + } + + tpg = nacl->se_tpg; + /* scsiAttIntrPortIndex */ + ret = snprintf(page, PAGE_SIZE, "%u\n", + TPG_TFO(tpg)->sess_get_index(se_sess)); + spin_unlock_irq(&nacl->nacl_sess_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(indx); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_port_auth_indx( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_dev_entry *deve; + ssize_t ret; + + spin_lock_irq(&nacl->device_list_lock); + deve = &nacl->device_list[lacl->mapped_lun]; + if (!deve->se_lun || !deve->se_lun_acl) { + spin_unlock_irq(&nacl->device_list_lock); + return -ENODEV; + } + /* scsiAttIntrPortAuthIntrIdx */ + ret = snprintf(page, PAGE_SIZE, "%u\n", nacl->acl_index); + spin_unlock_irq(&nacl->device_list_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_auth_indx); + +static ssize_t target_stat_scsi_att_intr_port_show_attr_port_ident( + struct se_ml_stat_grps *lgrps, char *page) +{ + struct se_lun_acl *lacl = container_of(lgrps, + struct se_lun_acl, ml_stat_grps); + struct se_node_acl *nacl = lacl->se_lun_nacl; + struct se_session *se_sess; + struct se_portal_group *tpg; + ssize_t ret; + unsigned char buf[64]; + + spin_lock_irq(&nacl->nacl_sess_lock); + se_sess = nacl->nacl_sess; + if (!se_sess) { + spin_unlock_irq(&nacl->nacl_sess_lock); + return -ENODEV; + } + + tpg = nacl->se_tpg; + /* scsiAttIntrPortName+scsiAttIntrPortIdentifier */ + memset(buf, 0, 64); + if (TPG_TFO(tpg)->sess_get_initiator_sid != NULL) + TPG_TFO(tpg)->sess_get_initiator_sid(se_sess, + (unsigned char *)&buf[0], 64); + + ret = snprintf(page, PAGE_SIZE, "%s+i+%s\n", nacl->initiatorname, buf); + spin_unlock_irq(&nacl->nacl_sess_lock); + return ret; +} +DEV_STAT_SCSI_ATTR_INTR_PORT_ATTR_RO(port_ident); + +CONFIGFS_EATTR_OPS(target_stat_scsi_att_intr_port, se_ml_stat_grps, + scsi_att_intr_port_group); + +static struct configfs_attribute *target_stat_scsi_ath_intr_port_attrs[] = { + &target_stat_scsi_att_intr_port_inst.attr, + &target_stat_scsi_att_intr_port_dev.attr, + &target_stat_scsi_att_intr_port_port.attr, + &target_stat_scsi_att_intr_port_indx.attr, + &target_stat_scsi_att_intr_port_port_auth_indx.attr, + &target_stat_scsi_att_intr_port_port_ident.attr, + NULL, +}; + +static struct configfs_item_operations target_stat_scsi_att_intr_port_attrib_ops = { + .show_attribute = target_stat_scsi_att_intr_port_attr_show, + .store_attribute = target_stat_scsi_att_intr_port_attr_store, +}; + +static struct config_item_type target_stat_scsi_att_intr_port_cit = { + .ct_item_ops = &target_stat_scsi_att_intr_port_attrib_ops, + .ct_attrs = target_stat_scsi_ath_intr_port_attrs, + .ct_owner = THIS_MODULE, +}; + +/* + * Called from target_core_fabric_configfs.c:target_fabric_make_mappedlun() to setup + * the target MappedLUN statistics groups + configfs CITs located in target_core_stat.c + */ +void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *lacl) +{ + struct config_group *ml_stat_grp = &ML_STAT_GRPS(lacl)->stat_group; + + config_group_init_type_name(&ML_STAT_GRPS(lacl)->scsi_auth_intr_group, + "scsi_auth_intr", &target_stat_scsi_auth_intr_cit); + config_group_init_type_name(&ML_STAT_GRPS(lacl)->scsi_att_intr_port_group, + "scsi_att_intr_port", &target_stat_scsi_att_intr_port_cit); + + ml_stat_grp->default_groups[0] = &ML_STAT_GRPS(lacl)->scsi_auth_intr_group; + ml_stat_grp->default_groups[1] = &ML_STAT_GRPS(lacl)->scsi_att_intr_port_group; + ml_stat_grp->default_groups[2] = NULL; +} diff --git a/drivers/target/target_core_stat.h b/drivers/target/target_core_stat.h new file mode 100644 index 000000000000..86c252f9ea47 --- /dev/null +++ b/drivers/target/target_core_stat.h @@ -0,0 +1,8 @@ +#ifndef TARGET_CORE_STAT_H +#define TARGET_CORE_STAT_H + +extern void target_stat_setup_dev_default_groups(struct se_subsystem_dev *); +extern void target_stat_setup_port_default_groups(struct se_lun *); +extern void target_stat_setup_mappedlun_default_groups(struct se_lun_acl *); + +#endif /*** TARGET_CORE_STAT_H ***/ diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 79f2e0a30dc8..c15ed5026fb5 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -601,7 +601,8 @@ struct se_node_acl { struct config_group acl_attrib_group; struct config_group acl_auth_group; struct config_group acl_param_group; - struct config_group *acl_default_groups[4]; + struct config_group acl_fabric_stat_group; + struct config_group *acl_default_groups[5]; struct list_head acl_list; struct list_head acl_sess_list; } ____cacheline_aligned; @@ -622,6 +623,12 @@ struct se_device; struct se_transform_info; struct scatterlist; +struct se_ml_stat_grps { + struct config_group stat_group; + struct config_group scsi_auth_intr_group; + struct config_group scsi_att_intr_port_group; +}; + struct se_lun_acl { char initiatorname[TRANSPORT_IQN_LEN]; u32 mapped_lun; @@ -629,8 +636,11 @@ struct se_lun_acl { struct se_lun *se_lun; struct list_head lacl_list; struct config_group se_lun_group; + struct se_ml_stat_grps ml_stat_grps; } ____cacheline_aligned; +#define ML_STAT_GRPS(lacl) (&(lacl)->ml_stat_grps) + struct se_dev_entry { bool def_pr_registered; /* See transport_lunflags_table */ @@ -693,6 +703,13 @@ struct se_dev_attrib { struct config_group da_group; } ____cacheline_aligned; +struct se_dev_stat_grps { + struct config_group stat_group; + struct config_group scsi_dev_group; + struct config_group scsi_tgt_dev_group; + struct config_group scsi_lu_group; +}; + struct se_subsystem_dev { /* Used for struct se_subsystem_dev-->se_dev_alias, must be less than PAGE_SIZE */ #define SE_DEV_ALIAS_LEN 512 @@ -716,11 +733,14 @@ struct se_subsystem_dev { struct config_group se_dev_group; /* For T10 Reservations */ struct config_group se_dev_pr_group; + /* For target_core_stat.c groups */ + struct se_dev_stat_grps dev_stat_grps; } ____cacheline_aligned; #define T10_ALUA(su_dev) (&(su_dev)->t10_alua) #define T10_RES(su_dev) (&(su_dev)->t10_reservation) #define T10_PR_OPS(su_dev) (&(su_dev)->t10_reservation.pr_ops) +#define DEV_STAT_GRP(dev) (&(dev)->dev_stat_grps) struct se_device { /* Set to 1 if thread is NOT sleeping on thread_sem */ @@ -834,6 +854,13 @@ struct se_hba { #define SE_HBA(dev) ((dev)->se_hba) +struct se_port_stat_grps { + struct config_group stat_group; + struct config_group scsi_port_group; + struct config_group scsi_tgt_port_group; + struct config_group scsi_transport_group; +}; + struct se_lun { /* See transport_lun_status_table */ enum transport_lun_status_table lun_status; @@ -848,11 +875,13 @@ struct se_lun { struct list_head lun_cmd_list; struct list_head lun_acl_list; struct se_device *lun_se_dev; + struct se_port *lun_sep; struct config_group lun_group; - struct se_port *lun_sep; + struct se_port_stat_grps port_stat_grps; } ____cacheline_aligned; #define SE_LUN(cmd) ((cmd)->se_lun) +#define PORT_STAT_GRP(lun) (&(lun)->port_stat_grps) struct scsi_port_stats { u64 cmd_pdus; @@ -924,6 +953,8 @@ struct se_portal_group { struct se_wwn { struct target_fabric_configfs *wwn_tf; struct config_group wwn_group; + struct config_group *wwn_default_groups[2]; + struct config_group fabric_stat_group; } ____cacheline_aligned; struct se_global { diff --git a/include/target/target_core_configfs.h b/include/target/target_core_configfs.h index 40e6e740527c..612509592ffd 100644 --- a/include/target/target_core_configfs.h +++ b/include/target/target_core_configfs.h @@ -14,10 +14,12 @@ extern void target_fabric_configfs_deregister(struct target_fabric_configfs *); struct target_fabric_configfs_template { struct config_item_type tfc_discovery_cit; struct config_item_type tfc_wwn_cit; + struct config_item_type tfc_wwn_fabric_stats_cit; struct config_item_type tfc_tpg_cit; struct config_item_type tfc_tpg_base_cit; struct config_item_type tfc_tpg_lun_cit; struct config_item_type tfc_tpg_port_cit; + struct config_item_type tfc_tpg_port_stat_cit; struct config_item_type tfc_tpg_np_cit; struct config_item_type tfc_tpg_np_base_cit; struct config_item_type tfc_tpg_attrib_cit; @@ -27,7 +29,9 @@ struct target_fabric_configfs_template { struct config_item_type tfc_tpg_nacl_attrib_cit; struct config_item_type tfc_tpg_nacl_auth_cit; struct config_item_type tfc_tpg_nacl_param_cit; + struct config_item_type tfc_tpg_nacl_stat_cit; struct config_item_type tfc_tpg_mappedlun_cit; + struct config_item_type tfc_tpg_mappedlun_stat_cit; }; struct target_fabric_configfs { -- cgit v1.2.3 From 70c7c88a1a65ca683eb7f3fe3ce79c72f29d845e Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Thu, 17 Mar 2011 16:22:17 -0500 Subject: [SCSI] libiscsi_tcp: use kmap in xmit path The xmit path can sleep with a page kmapped in the network xmit code while it waits for space to open up, so we have to use kmap instead of kmap atomic in that path. Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/libiscsi_tcp.c | 15 +++++++++++++-- include/scsi/libiscsi_tcp.h | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/drivers/scsi/libiscsi_tcp.c b/drivers/scsi/libiscsi_tcp.c index 8eeb39ffa37f..e98ae33f1295 100644 --- a/drivers/scsi/libiscsi_tcp.c +++ b/drivers/scsi/libiscsi_tcp.c @@ -132,14 +132,25 @@ static void iscsi_tcp_segment_map(struct iscsi_segment *segment, int recv) if (page_count(sg_page(sg)) >= 1 && !recv) return; - segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); + if (recv) { + segment->atomic_mapped = true; + segment->sg_mapped = kmap_atomic(sg_page(sg), KM_SOFTIRQ0); + } else { + segment->atomic_mapped = false; + /* the xmit path can sleep with the page mapped so use kmap */ + segment->sg_mapped = kmap(sg_page(sg)); + } + segment->data = segment->sg_mapped + sg->offset + segment->sg_offset; } void iscsi_tcp_segment_unmap(struct iscsi_segment *segment) { if (segment->sg_mapped) { - kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); + if (segment->atomic_mapped) + kunmap_atomic(segment->sg_mapped, KM_SOFTIRQ0); + else + kunmap(sg_page(segment->sg)); segment->sg_mapped = NULL; segment->data = NULL; } diff --git a/include/scsi/libiscsi_tcp.h b/include/scsi/libiscsi_tcp.h index 741ae7ed4394..e6b9fd2eea34 100644 --- a/include/scsi/libiscsi_tcp.h +++ b/include/scsi/libiscsi_tcp.h @@ -47,6 +47,7 @@ struct iscsi_segment { struct scatterlist *sg; void *sg_mapped; unsigned int sg_offset; + bool atomic_mapped; iscsi_segment_done_fn_t *done; }; -- cgit v1.2.3