From: Alexander Nezhinsky <alexandern@xxxxxxxxxxxx> To introduce statistics on SCSI device level we need to accumulate them for each ITL (initiator-target-lun) nexus. For example in case of iscsi, this is a granularity which is finer than a session (IT nexus), as it represents access to a specific lun within the session. Statistics counters are added to the ITL object, "struct it_nexus_lu_info". They need to be shown later in various scopes (connection, device, target etc.) requiring two-way access, both from a device (lun to all its ITLs) and from an IT nexus (IT nexus to all its ITLs). Thus linked list heads called "itn_itl_info_list" and "lu_itl_info_list" are added to struct it_nexus and struct scsi_lu, while struct it_nexus_lu_info becomes a memeber in these two lists, thru the list entries called: "itn_itl_info_siblings" and "lu_itl_info_siblings". Signed-off-by: Alexander Nezhinsky <alexandern@xxxxxxxxxxxx> --- usr/scsi.c | 18 ++++++++++-- usr/target.c | 91 +++++++++++++++++++++++++++++++++++++--------------------- usr/tgtd.h | 27 ++++++++++++++++- 3 files changed, 100 insertions(+), 36 deletions(-) diff --git a/usr/scsi.c b/usr/scsi.c index 83479ed..df28116 100644 --- a/usr/scsi.c +++ b/usr/scsi.c @@ -207,6 +207,20 @@ int scsi_cmd_perform(int host_no, struct scsi_cmd *cmd) unsigned char op = cmd->scb[0]; struct it_nexus_lu_info *itn_lu; + if (scsi_get_data_dir(cmd) == DATA_WRITE) { + cmd->itn_lu_info->stat.wr_subm_bytes += scsi_get_out_length(cmd); + cmd->itn_lu_info->stat.wr_subm_cmds++; + } + else if (scsi_get_data_dir(cmd) == DATA_READ) { + cmd->itn_lu_info->stat.rd_subm_bytes += scsi_get_in_length(cmd); + cmd->itn_lu_info->stat.rd_subm_cmds++; + } + else if (scsi_get_data_dir(cmd) == DATA_BIDIRECTIONAL) { + cmd->itn_lu_info->stat.wr_subm_bytes += scsi_get_out_length(cmd); + cmd->itn_lu_info->stat.rd_subm_bytes += scsi_get_in_length(cmd); + cmd->itn_lu_info->stat.bidir_subm_cmds++; + } + if (CDB_CONTROL(cmd) & ((1U << 0) | (1U << 2))) { /* * We don't support a linked command. SAM-3 say that @@ -241,8 +255,8 @@ int scsi_cmd_perform(int host_no, struct scsi_cmd *cmd) break; case REPORT_LUNS: list_for_each_entry(itn_lu, - &cmd->it_nexus->it_nexus_lu_info_list, - lu_info_siblings) + &cmd->it_nexus->itn_itl_info_list, + itn_itl_info_siblings) ua_sense_clear(itn_lu, ASC_REPORTED_LUNS_DATA_HAS_CHANGED); break; diff --git a/usr/target.c b/usr/target.c index 68222a0..ad951f9 100644 --- a/usr/target.c +++ b/usr/target.c @@ -81,7 +81,7 @@ static int target_name_lookup(char *name) return 0; } -static struct it_nexus *it_nexus_lookup(int tid, uint64_t itn_id) +struct it_nexus *it_nexus_lookup(int tid, uint64_t itn_id) { struct target *target; struct it_nexus *itn; @@ -196,14 +196,15 @@ static void it_nexus_del_lu_info(struct it_nexus *itn) { struct it_nexus_lu_info *itn_lu; - while(!list_empty(&itn->it_nexus_lu_info_list)) { - itn_lu = list_first_entry(&itn->it_nexus_lu_info_list, + while(!list_empty(&itn->itn_itl_info_list)) { + itn_lu = list_first_entry(&itn->itn_itl_info_list, struct it_nexus_lu_info, - lu_info_siblings); + itn_itl_info_siblings); ua_sense_pending_del(itn_lu); - list_del(&itn_lu->lu_info_siblings); + list_del(&itn_lu->itn_itl_info_siblings); + list_del(&itn_lu->lu_itl_info_siblings); free(itn_lu); } } @@ -220,8 +221,8 @@ void ua_sense_add_other_it_nexus(uint64_t itn_id, struct scsi_lu *lu, if (itn->itn_id == itn_id) continue; - list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + list_for_each_entry(itn_lu, &itn->itn_itl_info_list, + itn_itl_info_siblings) { if (itn_lu->lu != lu) continue; @@ -244,8 +245,8 @@ void ua_sense_add_it_nexus(uint64_t itn_id, struct scsi_lu *lu, list_for_each_entry(itn, &lu->tgt->it_nexus_list, nexus_siblings) { if (itn->itn_id == itn_id) { - list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + list_for_each_entry(itn_lu, &itn->itn_itl_info_list, + itn_itl_info_siblings) { if (itn_lu->lu == lu) { ret = ua_sense_add(itn_lu, asc); @@ -267,8 +268,8 @@ int lu_prevent_removal(struct scsi_lu *lu) struct it_nexus_lu_info *itn_lu; list_for_each_entry(itn, &lu->tgt->it_nexus_list, nexus_siblings) { - list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + list_for_each_entry(itn_lu, &itn->itn_itl_info_list, + itn_itl_info_siblings) { if (itn_lu->lu == lu) { if (itn_lu->prevent & PREVENT_REMOVAL) return 1; @@ -306,7 +307,7 @@ int it_nexus_create(int tid, uint64_t itn_id, int host_no, char *info) itn->host_no = host_no; itn->nexus_target = target; itn->info = info; - INIT_LIST_HEAD(&itn->it_nexus_lu_info_list); + INIT_LIST_HEAD(&itn->itn_itl_info_list); gettimeofday(&tv, NULL); itn->ctime = tv.tv_sec; @@ -315,14 +316,18 @@ int it_nexus_create(int tid, uint64_t itn_id, int host_no, char *info) if (!itn_lu) goto out; itn_lu->lu = lu; + itn_lu->itn_id = itn_id; INIT_LIST_HEAD(&itn_lu->pending_ua_sense_list); ret = ua_sense_add(itn_lu, ASC_POWERON_RESET); if (ret) goto out; - list_add(&itn_lu->lu_info_siblings, - &itn->it_nexus_lu_info_list); + list_add_tail(&itn_lu->lu_itl_info_siblings, + &lu->lu_itl_info_list); + + list_add(&itn_lu->itn_itl_info_siblings, + &itn->itn_itl_info_list); } INIT_LIST_HEAD(&itn->cmd_list); @@ -472,7 +477,7 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params, struct scsi_lu *lu, *pos; struct device_type_template *t; struct backingstore_template *bst; - struct it_nexus_lu_info *itn_lu; + struct it_nexus_lu_info *itn_lu, *itn_lu_pos; struct it_nexus *itn; char strflags[128]; @@ -573,6 +578,7 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params, tgt_cmd_queue_init(&lu->cmd_queue); INIT_LIST_HEAD(&lu->registration_list); + INIT_LIST_HEAD(&lu->lu_itl_info_list); lu->prgeneration = 0; lu->pr_holder = NULL; @@ -635,21 +641,24 @@ tgtadm_err tgt_device_create(int tid, int dev_type, uint64_t lun, char *params, if (!itn_lu) break; itn_lu->lu = lu; + itn_lu->itn_id = itn->itn_id; INIT_LIST_HEAD(&itn_lu->pending_ua_sense_list); - list_add(&itn_lu->lu_info_siblings, - &itn->it_nexus_lu_info_list); - } - - list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) { - list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + /* signal LUNs info change thru all existing LUNs in the nexus */ + list_for_each_entry(itn_lu_pos, &itn->itn_itl_info_list, + itn_itl_info_siblings) { - if (ua_sense_add(itn_lu, ASC_REPORTED_LUNS_DATA_HAS_CHANGED)) { + if (ua_sense_add(itn_lu_pos, ASC_REPORTED_LUNS_DATA_HAS_CHANGED)) { adm_err = TGTADM_NOMEM; goto fail_bs_init; } } + + list_add_tail(&itn_lu->lu_itl_info_siblings, + &lu->lu_itl_info_list); + + list_add(&itn_lu->itn_itl_info_siblings, + &itn->itn_itl_info_list); } if (backing && !path) @@ -711,8 +720,8 @@ tgtadm_err tgt_device_destroy(int tid, uint64_t lun, int force) lu->bst->bs_exit(lu); list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) { - list_for_each_entry_safe(itn_lu, next, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + list_for_each_entry_safe(itn_lu, next, &itn->itn_itl_info_list, + itn_itl_info_siblings) { if (itn_lu->lu == lu) { ua_sense_pending_del(itn_lu); break; @@ -730,8 +739,8 @@ tgtadm_err tgt_device_destroy(int tid, uint64_t lun, int force) free(lu); list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) { - list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + list_for_each_entry(itn_lu, &itn->itn_itl_info_list, + itn_itl_info_siblings) { ret = ua_sense_add(itn_lu, ASC_REPORTED_LUNS_DATA_HAS_CHANGED); @@ -951,8 +960,8 @@ static struct it_nexus_lu_info *it_nexus_lu_info_lookup(struct it_nexus *itn, { struct it_nexus_lu_info *itn_lu; - list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + list_for_each_entry(itn_lu, &itn->itn_itl_info_list, + itn_itl_info_siblings) { if (itn_lu->lu->lun == lun) return itn_lu; } @@ -1061,6 +1070,22 @@ int target_cmd_perform_passthrough(int tid, struct scsi_cmd *cmd) void target_cmd_io_done(struct scsi_cmd *cmd, int result) { scsi_set_result(cmd, result); + if (scsi_get_data_dir(cmd) == DATA_WRITE) { + cmd->itn_lu_info->stat.wr_done_bytes += scsi_get_out_length(cmd); + cmd->itn_lu_info->stat.wr_done_cmds++; + } + else if (scsi_get_data_dir(cmd) == DATA_READ) { + cmd->itn_lu_info->stat.rd_done_bytes += scsi_get_in_length(cmd); + cmd->itn_lu_info->stat.rd_done_cmds++; + } + else if (scsi_get_data_dir(cmd) == DATA_BIDIRECTIONAL) { + cmd->itn_lu_info->stat.wr_done_bytes += scsi_get_out_length(cmd); + cmd->itn_lu_info->stat.rd_done_bytes += scsi_get_in_length(cmd); + cmd->itn_lu_info->stat.bidir_done_cmds++; + } + if (result != SAM_STAT_GOOD) + cmd->itn_lu_info->stat.err_num++; + tgt_drivers[cmd->c_target->lid]->cmd_end_notify(cmd->cmd_itn_id, result, cmd); return; @@ -1241,8 +1266,8 @@ enum mgmt_req_result target_mgmt_request(int tid, uint64_t itn_id, send = 0; list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) { - list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + list_for_each_entry(itn_lu, &itn->itn_itl_info_list, + itn_itl_info_siblings) { if (itn_lu->lu->lun == lun) { if (itn->itn_id == itn_id) asc = ASC_POWERON_RESET; @@ -1263,8 +1288,8 @@ enum mgmt_req_result target_mgmt_request(int tid, uint64_t itn_id, send = 0; list_for_each_entry(itn, &target->it_nexus_list, nexus_siblings) { - list_for_each_entry(itn_lu, &itn->it_nexus_lu_info_list, - lu_info_siblings) { + list_for_each_entry(itn_lu, &itn->itn_itl_info_list, + itn_itl_info_siblings) { if (itn_lu->lu->lun == lun) { ua_sense_add(itn_lu, ASC_POWERON_RESET); break; diff --git a/usr/tgtd.h b/usr/tgtd.h index aa9b9d5..9fac774 100644 --- a/usr/tgtd.h +++ b/usr/tgtd.h @@ -92,9 +92,31 @@ struct ua_sense { int ua_sense_len; }; +struct lu_stat { + uint64_t rd_subm_bytes; + uint64_t rd_done_bytes; + + uint64_t wr_subm_bytes; + uint64_t wr_done_bytes; + + uint32_t rd_subm_cmds; + uint32_t rd_done_cmds; + + uint32_t wr_subm_cmds; + uint32_t wr_done_cmds; + + uint32_t bidir_subm_cmds; + uint32_t bidir_done_cmds; + + uint32_t err_num; +}; + struct it_nexus_lu_info { struct scsi_lu *lu; - struct list_head lu_info_siblings; + uint64_t itn_id; + struct lu_stat stat; + struct list_head itn_itl_info_siblings; + struct list_head lu_itl_info_siblings; struct list_head pending_ua_sense_list; int prevent; /* prevent removal on this itl nexus ? */ }; @@ -174,6 +196,8 @@ struct scsi_lu { /* the list of devices belonging to a target */ struct list_head device_siblings; + struct list_head lu_itl_info_list; + struct tgt_cmd_queue cmd_queue; uint64_t reserve_id; @@ -280,6 +304,7 @@ extern enum mgmt_req_result target_mgmt_request(int tid, uint64_t itn_id, uint8_t *lun, uint64_t tag, int host_no); +extern struct it_nexus *it_nexus_lookup(int tid, uint64_t itn_id); extern void target_cmd_io_done(struct scsi_cmd *cmd, int result); extern int ua_sense_del(struct scsi_cmd *cmd, int del); extern void ua_sense_clear(struct it_nexus_lu_info *itn_lu, uint16_t asc); -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html