/******************************************************************************* * Filename: target_core_mib.c * * Copyright (c) 2006-2007 SBE, Inc. All Rights Reserved. * Copyright (c) 2007-2010 Rising Tide Systems * Copyright (c) 2008-2010 Linux-iSCSI.org * * 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 "target_core_hba.h" #include "target_core_mib.h" /* SCSI mib table index */ static struct scsi_index_table scsi_index_table; #ifndef INITIAL_JIFFIES #define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) #endif /* SCSI Instance Table */ #define SCSI_INST_SW_INDEX 1 #define SCSI_TRANSPORT_INDEX 1 #define NONE "None" #define ISPRINT(a) ((a >= ' ') && (a <= '~')) static inline int list_is_first(const struct list_head *list, const struct list_head *head) { return list->prev == head; } static void *locate_hba_start( struct seq_file *seq, loff_t *pos) { spin_lock(&se_global->g_device_lock); return seq_list_start(&se_global->g_se_dev_list, *pos); } static void *locate_hba_next( struct seq_file *seq, void *v, loff_t *pos) { return seq_list_next(v, &se_global->g_se_dev_list, pos); } static void locate_hba_stop(struct seq_file *seq, void *v) { spin_unlock(&se_global->g_device_lock); } /**************************************************************************** * SCSI MIB Tables ****************************************************************************/ /* * SCSI Instance Table */ static void *scsi_inst_seq_start( struct seq_file *seq, loff_t *pos) { spin_lock(&se_global->hba_lock); return seq_list_start(&se_global->g_hba_list, *pos); } static void *scsi_inst_seq_next( struct seq_file *seq, void *v, loff_t *pos) { return seq_list_next(v, &se_global->g_hba_list, pos); } static void scsi_inst_seq_stop(struct seq_file *seq, void *v) { spin_unlock(&se_global->hba_lock); } static int scsi_inst_seq_show(struct seq_file *seq, void *v) { struct se_hba *hba = list_entry(v, struct se_hba, hba_list); if (list_is_first(&hba->hba_list, &se_global->g_hba_list)) seq_puts(seq, "inst sw_indx\n"); seq_printf(seq, "%u %u\n", hba->hba_index, SCSI_INST_SW_INDEX); seq_printf(seq, "plugin: %s version: %s\n", hba->transport->name, TARGET_CORE_VERSION); return 0; } static const struct seq_operations scsi_inst_seq_ops = { .start = scsi_inst_seq_start, .next = scsi_inst_seq_next, .stop = scsi_inst_seq_stop, .show = scsi_inst_seq_show }; static int scsi_inst_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_inst_seq_ops); } static const struct file_operations scsi_inst_seq_fops = { .owner = THIS_MODULE, .open = scsi_inst_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* * SCSI Device Table */ static void *scsi_dev_seq_start(struct seq_file *seq, loff_t *pos) { return locate_hba_start(seq, pos); } static void *scsi_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return locate_hba_next(seq, v, pos); } static void scsi_dev_seq_stop(struct seq_file *seq, void *v) { locate_hba_stop(seq, v); } static int scsi_dev_seq_show(struct seq_file *seq, void *v) { struct se_hba *hba; struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, g_se_dev_list); struct se_device *dev = se_dev->se_dev_ptr; char str[28]; int k; if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) seq_puts(seq, "inst indx role ports\n"); if (!(dev)) return 0; hba = dev->se_hba; if (!(hba)) { /* Log error ? */ return 0; } seq_printf(seq, "%u %u %s %u\n", hba->hba_index, dev->dev_index, "Target", dev->dev_port_count); memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); /* vendor */ for (k = 0; k < 8; k++) str[k] = ISPRINT(DEV_T10_WWN(dev)->vendor[k]) ? DEV_T10_WWN(dev)->vendor[k] : 0x20; str[k] = 0x20; /* model */ for (k = 0; k < 16; k++) str[k+9] = ISPRINT(DEV_T10_WWN(dev)->model[k]) ? DEV_T10_WWN(dev)->model[k] : 0x20; str[k + 9] = 0; seq_printf(seq, "dev_alias: %s\n", str); return 0; } static const struct seq_operations scsi_dev_seq_ops = { .start = scsi_dev_seq_start, .next = scsi_dev_seq_next, .stop = scsi_dev_seq_stop, .show = scsi_dev_seq_show }; static int scsi_dev_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_dev_seq_ops); } static const struct file_operations scsi_dev_seq_fops = { .owner = THIS_MODULE, .open = scsi_dev_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* * SCSI Port Table */ static void *scsi_port_seq_start(struct seq_file *seq, loff_t *pos) { return locate_hba_start(seq, pos); } static void *scsi_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return locate_hba_next(seq, v, pos); } static void scsi_port_seq_stop(struct seq_file *seq, void *v) { locate_hba_stop(seq, v); } static int scsi_port_seq_show(struct seq_file *seq, void *v) { struct se_hba *hba; struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, g_se_dev_list); struct se_device *dev = se_dev->se_dev_ptr; struct se_port *sep, *sep_tmp; if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) seq_puts(seq, "inst device indx role busy_count\n"); if (!(dev)) return 0; hba = dev->se_hba; if (!(hba)) { /* Log error ? */ return 0; } /* FIXME: scsiPortBusyStatuses count */ spin_lock(&dev->se_port_lock); list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { seq_printf(seq, "%u %u %u %s%u %u\n", hba->hba_index, dev->dev_index, sep->sep_index, "Device", dev->dev_index, 0); } spin_unlock(&dev->se_port_lock); return 0; } static const struct seq_operations scsi_port_seq_ops = { .start = scsi_port_seq_start, .next = scsi_port_seq_next, .stop = scsi_port_seq_stop, .show = scsi_port_seq_show }; static int scsi_port_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_port_seq_ops); } static const struct file_operations scsi_port_seq_fops = { .owner = THIS_MODULE, .open = scsi_port_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* * SCSI Transport Table */ static void *scsi_transport_seq_start(struct seq_file *seq, loff_t *pos) { return locate_hba_start(seq, pos); } static void *scsi_transport_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return locate_hba_next(seq, v, pos); } static void scsi_transport_seq_stop(struct seq_file *seq, void *v) { locate_hba_stop(seq, v); } static int scsi_transport_seq_show(struct seq_file *seq, void *v) { struct se_hba *hba; struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, g_se_dev_list); struct se_device *dev = se_dev->se_dev_ptr; struct se_port *se, *se_tmp; struct se_portal_group *tpg; struct t10_wwn *wwn; char buf[64]; if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) seq_puts(seq, "inst device indx dev_name\n"); if (!(dev)) return 0; hba = dev->se_hba; if (!(hba)) { /* Log error ? */ return 0; } wwn = DEV_T10_WWN(dev); spin_lock(&dev->se_port_lock); list_for_each_entry_safe(se, se_tmp, &dev->dev_sep_list, sep_list) { tpg = se->sep_tpg; sprintf(buf, "scsiTransport%s", TPG_TFO(tpg)->get_fabric_name()); seq_printf(seq, "%u %s %u %s+%s\n", hba->hba_index, /* scsiTransportIndex */ buf, /* scsiTransportType */ (TPG_TFO(tpg)->tpg_get_inst_index != NULL) ? TPG_TFO(tpg)->tpg_get_inst_index(tpg) : 0, TPG_TFO(tpg)->tpg_get_wwn(tpg), (strlen(wwn->unit_serial)) ? /* scsiTransportDevName */ wwn->unit_serial : wwn->vendor); } spin_unlock(&dev->se_port_lock); return 0; } static const struct seq_operations scsi_transport_seq_ops = { .start = scsi_transport_seq_start, .next = scsi_transport_seq_next, .stop = scsi_transport_seq_stop, .show = scsi_transport_seq_show }; static int scsi_transport_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_transport_seq_ops); } static const struct file_operations scsi_transport_seq_fops = { .owner = THIS_MODULE, .open = scsi_transport_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* * SCSI Target Device Table */ static void *scsi_tgt_dev_seq_start(struct seq_file *seq, loff_t *pos) { return locate_hba_start(seq, pos); } static void *scsi_tgt_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return locate_hba_next(seq, v, pos); } static void scsi_tgt_dev_seq_stop(struct seq_file *seq, void *v) { locate_hba_stop(seq, v); } #define LU_COUNT 1 /* for now */ static int scsi_tgt_dev_seq_show(struct seq_file *seq, void *v) { struct se_hba *hba; struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, g_se_dev_list); struct se_device *dev = se_dev->se_dev_ptr; int non_accessible_lus = 0; char status[16]; if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) seq_puts(seq, "inst indx num_LUs status non_access_LUs" " resets\n"); if (!(dev)) return 0; hba = dev->se_hba; if (!(hba)) { /* Log error ? */ return 0; } switch (dev->dev_status) { case TRANSPORT_DEVICE_ACTIVATED: strcpy(status, "activated"); break; case TRANSPORT_DEVICE_DEACTIVATED: strcpy(status, "deactivated"); non_accessible_lus = 1; break; case TRANSPORT_DEVICE_SHUTDOWN: strcpy(status, "shutdown"); non_accessible_lus = 1; break; case TRANSPORT_DEVICE_OFFLINE_ACTIVATED: case TRANSPORT_DEVICE_OFFLINE_DEACTIVATED: strcpy(status, "offline"); non_accessible_lus = 1; break; default: sprintf(status, "unknown(%d)", dev->dev_status); non_accessible_lus = 1; } seq_printf(seq, "%u %u %u %s %u %u\n", hba->hba_index, dev->dev_index, LU_COUNT, status, non_accessible_lus, dev->num_resets); return 0; } static const struct seq_operations scsi_tgt_dev_seq_ops = { .start = scsi_tgt_dev_seq_start, .next = scsi_tgt_dev_seq_next, .stop = scsi_tgt_dev_seq_stop, .show = scsi_tgt_dev_seq_show }; static int scsi_tgt_dev_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_tgt_dev_seq_ops); } static const struct file_operations scsi_tgt_dev_seq_fops = { .owner = THIS_MODULE, .open = scsi_tgt_dev_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* * SCSI Target Port Table */ static void *scsi_tgt_port_seq_start(struct seq_file *seq, loff_t *pos) { return locate_hba_start(seq, pos); } static void *scsi_tgt_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return locate_hba_next(seq, v, pos); } static void scsi_tgt_port_seq_stop(struct seq_file *seq, void *v) { locate_hba_stop(seq, v); } static int scsi_tgt_port_seq_show(struct seq_file *seq, void *v) { struct se_hba *hba; struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, g_se_dev_list); struct se_device *dev = se_dev->se_dev_ptr; struct se_port *sep, *sep_tmp; struct se_portal_group *tpg; u32 rx_mbytes, tx_mbytes; unsigned long long num_cmds; char buf[64]; if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) seq_puts(seq, "inst device indx name port_index in_cmds" " write_mbytes read_mbytes hs_in_cmds\n"); if (!(dev)) return 0; hba = dev->se_hba; if (!(hba)) { /* Log error ? */ return 0; } spin_lock(&dev->se_port_lock); list_for_each_entry_safe(sep, sep_tmp, &dev->dev_sep_list, sep_list) { tpg = sep->sep_tpg; sprintf(buf, "%sPort#", TPG_TFO(tpg)->get_fabric_name()); seq_printf(seq, "%u %u %u %s%d %s%s%d ", hba->hba_index, dev->dev_index, sep->sep_index, buf, sep->sep_index, TPG_TFO(tpg)->tpg_get_wwn(tpg), "+t+", TPG_TFO(tpg)->tpg_get_tag(tpg)); spin_lock(&sep->sep_lun->lun_sep_lock); num_cmds = sep->sep_stats.cmd_pdus; rx_mbytes = (sep->sep_stats.rx_data_octets >> 20); tx_mbytes = (sep->sep_stats.tx_data_octets >> 20); spin_unlock(&sep->sep_lun->lun_sep_lock); seq_printf(seq, "%llu %u %u %u\n", num_cmds, rx_mbytes, tx_mbytes, 0); } spin_unlock(&dev->se_port_lock); return 0; } static const struct seq_operations scsi_tgt_port_seq_ops = { .start = scsi_tgt_port_seq_start, .next = scsi_tgt_port_seq_next, .stop = scsi_tgt_port_seq_stop, .show = scsi_tgt_port_seq_show }; static int scsi_tgt_port_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_tgt_port_seq_ops); } static const struct file_operations scsi_tgt_port_seq_fops = { .owner = THIS_MODULE, .open = scsi_tgt_port_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* * SCSI Authorized Initiator Table: * It contains the SCSI Initiators authorized to be attached to one of the * local Target ports. * Iterates through all active TPGs and extracts the info from the ACLs */ static void *scsi_auth_intr_seq_start(struct seq_file *seq, loff_t *pos) { spin_lock_bh(&se_global->se_tpg_lock); return seq_list_start(&se_global->g_se_tpg_list, *pos); } static void *scsi_auth_intr_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return seq_list_next(v, &se_global->g_se_tpg_list, pos); } static void scsi_auth_intr_seq_stop(struct seq_file *seq, void *v) { spin_unlock_bh(&se_global->se_tpg_lock); } static int scsi_auth_intr_seq_show(struct seq_file *seq, void *v) { struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group, se_tpg_list); struct se_dev_entry *deve; struct se_lun *lun; struct se_node_acl *se_nacl; int j; if (list_is_first(&se_tpg->se_tpg_list, &se_global->g_se_tpg_list)) seq_puts(seq, "inst dev port indx dev_or_port intr_name " "map_indx att_count num_cmds read_mbytes " "write_mbytes hs_num_cmds creation_time row_status\n"); if (!(se_tpg)) return 0; spin_lock(&se_tpg->acl_node_lock); list_for_each_entry(se_nacl, &se_tpg->acl_node_list, acl_list) { atomic_inc(&se_nacl->mib_ref_count); smp_mb__after_atomic_inc(); spin_unlock(&se_tpg->acl_node_lock); spin_lock_irq(&se_nacl->device_list_lock); for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) { deve = &se_nacl->device_list[j]; if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) || (!deve->se_lun)) continue; lun = deve->se_lun; if (!lun->lun_se_dev) continue; seq_printf(seq, "%u %u %u %u %u %s %u %u %u %u %u %u" " %u %s\n", /* scsiInstIndex */ (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ? TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) : 0, /* scsiDeviceIndex */ lun->lun_se_dev->dev_index, /* scsiAuthIntrTgtPortIndex */ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg), /* scsiAuthIntrIndex */ se_nacl->acl_index, /* scsiAuthIntrDevOrPort */ 1, /* scsiAuthIntrName */ se_nacl->initiatorname[0] ? se_nacl->initiatorname : NONE, /* FIXME: scsiAuthIntrLunMapIndex */ 0, /* scsiAuthIntrAttachedTimes */ deve->attach_count, /* scsiAuthIntrOutCommands */ deve->total_cmds, /* scsiAuthIntrReadMegaBytes */ (u32)(deve->read_bytes >> 20), /* scsiAuthIntrWrittenMegaBytes */ (u32)(deve->write_bytes >> 20), /* FIXME: scsiAuthIntrHSOutCommands */ 0, /* scsiAuthIntrLastCreation */ (u32)(((u32)deve->creation_time - INITIAL_JIFFIES) * 100 / HZ), /* FIXME: scsiAuthIntrRowStatus */ "Ready"); } spin_unlock_irq(&se_nacl->device_list_lock); spin_lock(&se_tpg->acl_node_lock); atomic_dec(&se_nacl->mib_ref_count); smp_mb__after_atomic_dec(); } spin_unlock(&se_tpg->acl_node_lock); return 0; } static const struct seq_operations scsi_auth_intr_seq_ops = { .start = scsi_auth_intr_seq_start, .next = scsi_auth_intr_seq_next, .stop = scsi_auth_intr_seq_stop, .show = scsi_auth_intr_seq_show }; static int scsi_auth_intr_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_auth_intr_seq_ops); } static const struct file_operations scsi_auth_intr_seq_fops = { .owner = THIS_MODULE, .open = scsi_auth_intr_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* * SCSI Attached Initiator Port Table: * It lists the SCSI Initiators attached to one of the local Target ports. * Iterates through all active TPGs and use active sessions from each TPG * to list the info fo this table. */ static void *scsi_att_intr_port_seq_start(struct seq_file *seq, loff_t *pos) { spin_lock_bh(&se_global->se_tpg_lock); return seq_list_start(&se_global->g_se_tpg_list, *pos); } static void *scsi_att_intr_port_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return seq_list_next(v, &se_global->g_se_tpg_list, pos); } static void scsi_att_intr_port_seq_stop(struct seq_file *seq, void *v) { spin_unlock_bh(&se_global->se_tpg_lock); } static int scsi_att_intr_port_seq_show(struct seq_file *seq, void *v) { struct se_portal_group *se_tpg = list_entry(v, struct se_portal_group, se_tpg_list); struct se_dev_entry *deve; struct se_lun *lun; struct se_node_acl *se_nacl; struct se_session *se_sess; unsigned char buf[64]; int j; if (list_is_first(&se_tpg->se_tpg_list, &se_global->g_se_tpg_list)) seq_puts(seq, "inst dev port indx port_auth_indx port_name" " port_ident\n"); if (!(se_tpg)) return 0; spin_lock(&se_tpg->session_lock); list_for_each_entry(se_sess, &se_tpg->tpg_sess_list, sess_list) { if ((TPG_TFO(se_tpg)->sess_logged_in(se_sess)) || (!se_sess->se_node_acl) || (!se_sess->se_node_acl->device_list)) continue; atomic_inc(&se_sess->mib_ref_count); smp_mb__after_atomic_inc(); se_nacl = se_sess->se_node_acl; atomic_inc(&se_nacl->mib_ref_count); smp_mb__after_atomic_inc(); spin_unlock(&se_tpg->session_lock); spin_lock_irq(&se_nacl->device_list_lock); for (j = 0; j < TRANSPORT_MAX_LUNS_PER_TPG; j++) { deve = &se_nacl->device_list[j]; if (!(deve->lun_flags & TRANSPORT_LUNFLAGS_INITIATOR_ACCESS) || (!deve->se_lun)) continue; lun = deve->se_lun; if (!lun->lun_se_dev) continue; memset(buf, 0, 64); if (TPG_TFO(se_tpg)->sess_get_initiator_sid != NULL) TPG_TFO(se_tpg)->sess_get_initiator_sid( se_sess, (unsigned char *)&buf[0], 64); seq_printf(seq, "%u %u %u %u %u %s+i+%s\n", /* scsiInstIndex */ (TPG_TFO(se_tpg)->tpg_get_inst_index != NULL) ? TPG_TFO(se_tpg)->tpg_get_inst_index(se_tpg) : 0, /* scsiDeviceIndex */ lun->lun_se_dev->dev_index, /* scsiPortIndex */ TPG_TFO(se_tpg)->tpg_get_tag(se_tpg), /* scsiAttIntrPortIndex */ (TPG_TFO(se_tpg)->sess_get_index != NULL) ? TPG_TFO(se_tpg)->sess_get_index(se_sess) : 0, /* scsiAttIntrPortAuthIntrIdx */ se_nacl->acl_index, /* scsiAttIntrPortName */ se_nacl->initiatorname[0] ? se_nacl->initiatorname : NONE, /* scsiAttIntrPortIdentifier */ buf); } spin_unlock_irq(&se_nacl->device_list_lock); spin_lock(&se_tpg->session_lock); atomic_dec(&se_nacl->mib_ref_count); smp_mb__after_atomic_dec(); atomic_dec(&se_sess->mib_ref_count); smp_mb__after_atomic_dec(); } spin_unlock(&se_tpg->session_lock); return 0; } static const struct seq_operations scsi_att_intr_port_seq_ops = { .start = scsi_att_intr_port_seq_start, .next = scsi_att_intr_port_seq_next, .stop = scsi_att_intr_port_seq_stop, .show = scsi_att_intr_port_seq_show }; static int scsi_att_intr_port_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_att_intr_port_seq_ops); } static const struct file_operations scsi_att_intr_port_seq_fops = { .owner = THIS_MODULE, .open = scsi_att_intr_port_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /* * SCSI Logical Unit Table */ static void *scsi_lu_seq_start(struct seq_file *seq, loff_t *pos) { return locate_hba_start(seq, pos); } static void *scsi_lu_seq_next(struct seq_file *seq, void *v, loff_t *pos) { return locate_hba_next(seq, v, pos); } static void scsi_lu_seq_stop(struct seq_file *seq, void *v) { locate_hba_stop(seq, v); } #define SCSI_LU_INDEX 1 static int scsi_lu_seq_show(struct seq_file *seq, void *v) { struct se_hba *hba; struct se_subsystem_dev *se_dev = list_entry(v, struct se_subsystem_dev, g_se_dev_list); struct se_device *dev = se_dev->se_dev_ptr; int j; char str[28]; if (list_is_first(&se_dev->g_se_dev_list, &se_global->g_se_dev_list)) seq_puts(seq, "inst dev indx LUN lu_name vend prod rev" " dev_type status state-bit num_cmds read_mbytes" " write_mbytes resets full_stat hs_num_cmds creation_time\n"); if (!(dev)) return 0; hba = dev->se_hba; if (!(hba)) { /* Log error ? */ return 0; } /* Fix LU state, if we can read it from the device */ seq_printf(seq, "%u %u %u %llu %s", hba->hba_index, dev->dev_index, SCSI_LU_INDEX, (unsigned long long)0, /* FIXME: scsiLuDefaultLun */ (strlen(DEV_T10_WWN(dev)->unit_serial)) ? /* scsiLuWwnName */ (char *)&DEV_T10_WWN(dev)->unit_serial[0] : "None"); memcpy(&str[0], (void *)DEV_T10_WWN(dev), 28); /* scsiLuVendorId */ 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; seq_printf(seq, " %s", str); /* scsiLuProductId */ 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; seq_printf(seq, " %s", str); /* scsiLuRevisionId */ 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; seq_printf(seq, " %s", str); seq_printf(seq, " %u %s %s %llu %u %u %u %u %u %u\n", /* scsiLuPeripheralType */ TRANSPORT(dev)->get_device_type(dev), (dev->dev_status == TRANSPORT_DEVICE_ACTIVATED) ? "available" : "notavailable", /* scsiLuStatus */ "exposed", /* scsiLuState */ (unsigned long long)dev->num_cmds, /* scsiLuReadMegaBytes */ (u32)(dev->read_bytes >> 20), /* scsiLuWrittenMegaBytes */ (u32)(dev->write_bytes >> 20), dev->num_resets, /* scsiLuInResets */ 0, /* scsiLuOutTaskSetFullStatus */ 0, /* scsiLuHSInCommands */ (u32)(((u32)dev->creation_time - INITIAL_JIFFIES) * 100 / HZ)); return 0; } static const struct seq_operations scsi_lu_seq_ops = { .start = scsi_lu_seq_start, .next = scsi_lu_seq_next, .stop = scsi_lu_seq_stop, .show = scsi_lu_seq_show }; static int scsi_lu_seq_open(struct inode *inode, struct file *file) { return seq_open(file, &scsi_lu_seq_ops); } static const struct file_operations scsi_lu_seq_fops = { .owner = THIS_MODULE, .open = scsi_lu_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release, }; /****************************************************************************/ /* * Remove proc fs entries */ void remove_scsi_target_mib(void) { remove_proc_entry("scsi_target/mib/scsi_inst", NULL); remove_proc_entry("scsi_target/mib/scsi_dev", NULL); remove_proc_entry("scsi_target/mib/scsi_port", NULL); remove_proc_entry("scsi_target/mib/scsi_transport", NULL); remove_proc_entry("scsi_target/mib/scsi_tgt_dev", NULL); remove_proc_entry("scsi_target/mib/scsi_tgt_port", NULL); remove_proc_entry("scsi_target/mib/scsi_auth_intr", NULL); remove_proc_entry("scsi_target/mib/scsi_att_intr_port", NULL); remove_proc_entry("scsi_target/mib/scsi_lu", NULL); remove_proc_entry("scsi_target/mib", NULL); } /* * Create proc fs entries for the mib tables */ int init_scsi_target_mib(void) { struct proc_dir_entry *dir_entry; struct proc_dir_entry *scsi_inst_entry; struct proc_dir_entry *scsi_dev_entry; struct proc_dir_entry *scsi_port_entry; struct proc_dir_entry *scsi_transport_entry; struct proc_dir_entry *scsi_tgt_dev_entry; struct proc_dir_entry *scsi_tgt_port_entry; struct proc_dir_entry *scsi_auth_intr_entry; struct proc_dir_entry *scsi_att_intr_port_entry; struct proc_dir_entry *scsi_lu_entry; dir_entry = proc_mkdir("scsi_target/mib", NULL); if (!(dir_entry)) { printk(KERN_ERR "proc_mkdir() failed.\n"); return -1; } scsi_inst_entry = create_proc_entry("scsi_target/mib/scsi_inst", 0, NULL); if (scsi_inst_entry) scsi_inst_entry->proc_fops = &scsi_inst_seq_fops; else goto error; scsi_dev_entry = create_proc_entry("scsi_target/mib/scsi_dev", 0, NULL); if (scsi_dev_entry) scsi_dev_entry->proc_fops = &scsi_dev_seq_fops; else goto error; scsi_port_entry = create_proc_entry("scsi_target/mib/scsi_port", 0, NULL); if (scsi_port_entry) scsi_port_entry->proc_fops = &scsi_port_seq_fops; else goto error; scsi_transport_entry = create_proc_entry("scsi_target/mib/scsi_transport", 0, NULL); if (scsi_transport_entry) scsi_transport_entry->proc_fops = &scsi_transport_seq_fops; else goto error; scsi_tgt_dev_entry = create_proc_entry("scsi_target/mib/scsi_tgt_dev", 0, NULL); if (scsi_tgt_dev_entry) scsi_tgt_dev_entry->proc_fops = &scsi_tgt_dev_seq_fops; else goto error; scsi_tgt_port_entry = create_proc_entry("scsi_target/mib/scsi_tgt_port", 0, NULL); if (scsi_tgt_port_entry) scsi_tgt_port_entry->proc_fops = &scsi_tgt_port_seq_fops; else goto error; scsi_auth_intr_entry = create_proc_entry("scsi_target/mib/scsi_auth_intr", 0, NULL); if (scsi_auth_intr_entry) scsi_auth_intr_entry->proc_fops = &scsi_auth_intr_seq_fops; else goto error; scsi_att_intr_port_entry = create_proc_entry("scsi_target/mib/scsi_att_intr_port", 0, NULL); if (scsi_att_intr_port_entry) scsi_att_intr_port_entry->proc_fops = &scsi_att_intr_port_seq_fops; else goto error; scsi_lu_entry = create_proc_entry("scsi_target/mib/scsi_lu", 0, NULL); if (scsi_lu_entry) scsi_lu_entry->proc_fops = &scsi_lu_seq_fops; else goto error; return 0; error: printk(KERN_ERR "create_proc_entry() failed.\n"); remove_scsi_target_mib(); return -1; } /* * Initialize the index table for allocating unique row indexes to various mib * tables */ void init_scsi_index_table(void) { memset(&scsi_index_table, 0, sizeof(struct scsi_index_table)); spin_lock_init(&scsi_index_table.lock); } /* * Allocate a new row index for the entry type specified */ u32 scsi_get_new_index(scsi_index_t type) { u32 new_index; if ((type < 0) || (type >= SCSI_INDEX_TYPE_MAX)) { printk(KERN_ERR "Invalid index type %d\n", type); return -1; } spin_lock(&scsi_index_table.lock); new_index = ++scsi_index_table.scsi_mib_index[type]; if (new_index == 0) new_index = ++scsi_index_table.scsi_mib_index[type]; spin_unlock(&scsi_index_table.lock); return new_index; } EXPORT_SYMBOL(scsi_get_new_index);