📄 initiator_proc_iface.c
字号:
/* initiator/initiator_proc_iface.c * * vi: set autoindent tabstop=8 shiftwidth=8 : * * This file contains the functions for iscsi initiator code that are * responsible for interfacing with the /proc filesystem. * * Copyright (C) 2001-2004 InterOperability Lab (IOL) * University of New Hampshire (UNH) * Durham, NH 03824 * * 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, 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. * * The name IOL and/or UNH may not be used to endorse or promote * products derived from this software without specific prior * written permission.*/#include "iscsi_initiator.h"#include "initiator_utilities.h"#include "initiator_error_rec.h"#include "initiator_proc_iface.h"#include <linux/proc_fs.h>#ifdef ISCSI_STATSstatic int __attribute__ ((no_instrument_function))dump_conn_info(struct connection *, char *);static int __attribute__ ((no_instrument_function))dump_sess_info(struct session *, char *);static int __attribute__ ((no_instrument_function))dump_instance_stats(char *);#endif/* * executed only by command process. * Called only by scan_test_stuff() * returns >= 0 on success, * < 0 on error */static int __attribute__ ((no_instrument_function))do_test(__u32 target, __u32 cid, __u32 test_no){ unsigned long flags, lock_flags; int result; struct connection *conn; struct session *sess; /* When using session list, be sure nobody else accesses it */ UNH_LOCK(&host_data_lock, flags); /* use target and cid to find session and connection */ result = find_connection(target, cid, global_hostdata, &conn, &sess); if (result >= 0) { /* perform the requested test on this connection */ UNH_LOCK(&sess->sess_lock, lock_flags); UNH_UNLOCK(&host_data_lock, flags); TRACE(TRACE_ISCSI, "Do test number %u\n", test_no); switch (test_no) { case 0: /* send text request */ result = drive_text_negotiate(conn, sess, 0, 1); break; case 1: /* send text request as immediate cmd */ result = drive_text_negotiate(conn, sess, I_BIT, 1); break; case 2: /* send nop (not immediate, no data) */ result = drive_nopout(conn, sess, 0, 0); break; case 3: /* send nop (immediate, no data) */ result = drive_nopout(conn, sess, I_BIT, 0); break; case 4: /* send nop ping (not immediate, data) */ result = drive_nopout(conn, sess, 0, 1); break; case 5: /* send nop ping (immediate, data) */ result = drive_nopout(conn, sess, I_BIT, 1); break; case 6: /* stop/start responding to nop ping from target */ conn->connection_flags ^= SEND_NO_REPLY_TO_NOP_PING; break; case 7: /* stop/start responding to async logout * request from target */ conn->connection_flags ^= SEND_NO_REPLY_TO_ASYNC_LOGOUT; break; case 8: /* perform connection re-assignment - SAI */ conn->rec_tests = test_no; break; case 9: /* send session logout request */ result = !drive_logout(sess, conn, LOGOUT_CLOSE_SESSION); break; case 10: /* send connection logout request */ result = !drive_logout(sess, conn, LOGOUT_CLOSE_CONNECTION); break; default: TRACE_ERROR("Test number %u not implemented yet\n", test_no); result = -EINVAL; break; } /* switch */ UNH_UNLOCK(&sess->sess_lock, lock_flags); } else { /* release our exclusive access to the iscsi structures */ UNH_UNLOCK(&host_data_lock, flags); } return result;}/* * executed only by command process. * host_data_lock MUST be held by the calling process/thread * Called by dump_conn_info() and print_session_info() */static int __attribute__ ((no_instrument_function))print_connection_info( struct connection *conn, char *buffer, int pos ){ const char *ptr; int lun; struct session *sess; char extra[20]; pos += sprintf(buffer + pos, "%16s: %u\n", "Connection CID", conn->connection_id); pos += sprintf(buffer + pos, "%16s: ", "Connection State"); switch (conn->connection_state) { case CONNECTION_FULL_FEATURE_PHASE: ptr = "FULL FEATURE PHASE"; break; case CONNECTION_LOGGED_IN: case CONNECTION_CONNECTED: ptr = "LOGIN PHASE"; break; case CONNECTION_RECOVERING: ptr = "ERROR RECOVERY"; break; case CONNECTION_LOGGED_OUT: case CONNECTION_DISCONNECTED: ptr = "LOGOUT PHASE"; break; case CONNECTION_NOT_PRESENT: ptr = "NOT CONNECTED"; break; default: pos += sprintf(buffer + pos, "0x%x", conn->connection_state); ptr = ""; break; } pos += sprintf(buffer + pos, "%s\n", ptr); if (conn->connection_state == CONNECTION_FULL_FEATURE_PHASE || conn->connection_state == CONNECTION_CONNECTED) { char ip_string[INET6_ADDRSTRLEN+2], port_string[8]; if (cnv_inet_to_string(conn->ip_address, ip_string, port_string) > 0) { pos += sprintf(buffer + pos, "%16s: %s:%s\n", "Target Address", ip_string, port_string); } if (cnv_inet_to_string(conn->local_ip_address, ip_string, port_string) > 0) { pos += sprintf(buffer + pos, "%16s: %s:%s\n", "Local Address", ip_string, port_string); } sess = conn->my_session; if (sess->sched_scheme == CONN_SCHED_LUN ) { /* LUN assigned to connection scheduling is in effect, * print numbers of all luns assigned to this connection * (if any) */ lun = conn->assigned_lun_count; sprintf(extra, "%d assigned LUN%s", lun, lun == 1 ? "" : "s"); pos += sprintf(buffer + pos, "%16s:", extra); for (lun = 0; lun < MAX_LUNS; lun++) { if (conn == sess->lun_assignments[lun]) { pos += sprintf(buffer + pos," %d",lun); } } pos += sprintf(buffer + pos, "\n"); } } return pos;}static int __attribute__ ((no_instrument_function))print_ascii(char *buffer, __u8 *ptr, int len, char *mess){ int pos; pos = sprintf(buffer, "%24s: ", mess); memcpy(buffer + pos, ptr, len); pos += len; pos += sprintf(buffer + pos, "\n"); return pos;}static int __attribute__ ((no_instrument_function))print_ver_descr(char *buffer, __u8 *ptr, __u8 *base){ int pos = 0, i; for (i = 0; i < 8; i++) { if (ptr > base) break; if (*ptr || *(ptr+1)) { pos += sprintf(buffer + pos, "%24s: 0x%02x%02x\n", "version descriptor", *ptr, *(ptr+1)); } ptr += 2; } return pos;}static int __attribute__ ((no_instrument_function))print_capacity_stuff(char *buffer, struct session *sess, __u32 lun){ int pos = 0; __u32 lba = sess->capacity_lba[lun]; __u32 len = sess->capacity_len[lun]; if (lba && len) { if (lba != ALL_ONES) lba++; pos = sprintf(buffer + pos, "%16s: %u %u %u-byte hardware sectors\n", "capacity for lun", lun, lba, len); } return pos;}static int __attribute__ ((no_instrument_function))print_limits_stuff(char *buffer, struct session *sess, __u32 lun){ int pos = 0; __u32 max = sess->limit_max[lun]; __u32 min = sess->limit_min[lun]; if (max || min) { pos = sprintf(buffer + pos, "%16s: %u [%u, %u] bytes per block\n", "limits for lun", lun, min, max); } return pos;}static const char * __attribute__ ((no_instrument_function))printable_dev_type( __u32 dev_type ){ const char *mess; if (dev_type < MAX_SCSI_DEVICE_CODE) { mess = scsi_device_types[dev_type]; } else { mess = "reserved"; switch (dev_type) { case 0x0e: mess = "simple-direct-access"; break; case 0x0f: mess = "optical card reader/writer"; break; case 0x11: mess = "object-based-storage"; break; case 0x1f: mess = "unknown"; break; } /* switch */ } return mess;}static int __attribute__ ((no_instrument_function))print_inquiry_stuff(char *buffer, struct session *sess, __u32 lun){ int pos = 0, size = sess->inquiry_size[lun], len; __u8 *base = sess->inquiry_buf[lun], *ptr; if ((ptr = base) && size) { pos += sprintf(buffer + pos, "%16s: %u (bytes 0..%u)\n", "inquiry for lun", lun, *(ptr + 4) + 4); if ((*ptr >> 5) == 0) pos += sprintf(buffer + pos, "%24s: %s\n", "device", "connected"); else if ((*ptr >> 5) == 1) pos += sprintf(buffer + pos, "%24s: %s\n", "device", "not connected"); else pos += sprintf(buffer + pos, "%24s: %u\n", "qualifier", *ptr >> 5); pos += sprintf(buffer + pos, "%24s: %s\n", "device type", printable_dev_type(*ptr & 0x1f)); ptr += 1; pos += sprintf(buffer + pos, "%24s: %sremovable\n", "medium", *ptr & 0x80 ? "" : "not "); ptr += 1; pos += sprintf(buffer + pos, "%24s: 0x%02x\n", "version", *ptr); ptr += 1; if (*ptr != 2) pos += sprintf(buffer + pos, "%24s: 0x%02x\n", "byte 3", *ptr); ptr += 1; base += 4 + *ptr++; if (ptr > base) goto done; if (*ptr & 0x80) pos =+ sprintf(buffer + pos, "%24s: %s\n", "device contains", "embedded storage array controller"); ptr += 1; /* skip byte 5 for now */ if (ptr > base) goto done; pos += sprintf(buffer + pos, "%24s: 0x%02x\n", "byte 6", *ptr); ptr += 1; if (ptr > base) goto done; pos += sprintf(buffer + pos, "%24s: 0x%02x\n", "byte 7", *ptr); ptr += 1; if (ptr > base) goto done; pos += print_ascii(buffer + pos, ptr, 8, "vendor id"); ptr += 8; if (ptr > base) goto done; pos += print_ascii(buffer + pos, ptr, 16, "product id"); ptr += 16; if (ptr > base) goto done; pos += print_ascii(buffer + pos, ptr, 4, "product revision"); ptr += 4; if (ptr > base) goto done; len = strlen(ptr); if (len > 0 && len < 20) pos += sprintf(buffer + pos, "%24s: %s\n", "vendor specific", ptr); ptr += 20; if (ptr > base) goto done; pos += sprintf(buffer + pos, "%24s: 0x%02x\n", "byte 56", *ptr); ptr += 1 + 1; pos += print_ver_descr(buffer + pos, ptr, base); }done: return pos;}/* * executed only by command process. * host_data_lock MUST be held by the calling process/thread * Called by dump_sess_info() and iscsi_initiator_proc_info() * this is for configuring the login parameters */static int __attribute__ ((no_instrument_function))print_session_info( struct session *sess, char *buffer, int pos ){ int i; struct connection *conn; const char *ptr; char extra[12]; pos += sprintf(buffer + pos, "%16s: 0x%p\n", "pointer", sess); pos += sprintf(buffer + pos, "%16s: %u\n", "target id", sess->scsi_target_id); sprintf(extra, "%u LUN%s", sess->n_luns_in_session, sess->n_luns_in_session == 1 ? "" : "s"); pos += sprintf(buffer + pos, "%16s:", extra); for (i = 0; i < global_host->max_lun; i++) { if (sess->lun_bits & (1 << i)) { pos += sprintf(buffer + pos, " %d", i); } } pos += sprintf(buffer + pos, "\n"); for (i = 0; i < global_host->max_lun; i++) { if (sess->lun_bits & (1 << i)) { pos += print_capacity_stuff(buffer + pos, sess, i); pos += print_limits_stuff(buffer + pos, sess, i); pos += print_inquiry_stuff(buffer + pos, sess, i); } } switch (sess->sched_scheme) { case CONN_SCHED_RR: ptr = "round-robin"; break; case CONN_SCHED_LUN: ptr = "LUN to connection"; break; default: ptr = "first connection only"; break; } pos += sprintf(buffer + pos, "%16s: %s\n", "conn. scheduling", ptr); pos += sprintf(buffer + pos, "%16s: %u\n", "nop interval", sess->nop_period); pos += sprintf(buffer + pos, "%16s: %u\n", "connections", sess->nconnections); for (conn = sess->connection_head; conn != NULL; conn = conn->next) { pos = print_connection_info(conn, buffer, pos); } return pos;}/* * executed only by command process. * host_data_lock MUST be held by the calling process/thread * Called by iscsi_initiator_proc_info() */static int __attribute__ ((no_instrument_function))print_host_info( struct Scsi_Host *host, char *buffer, int pos ){ pos += sprintf(buffer + pos, "%24s %u\n", "host number", host->host_no); pos += sprintf(buffer + pos, "%24s %u\n", "max targets", host->max_id); pos += sprintf(buffer + pos, "%24s %u\n", "max luns per target", host->max_lun); pos += sprintf(buffer + pos, "%24s %u\n", "max bytes per cdb", host->max_cmd_len); pos += sprintf(buffer + pos, "%24s %d\n", "max outstanding commands", host->can_queue); pos += sprintf(buffer + pos, "%24s %d\n", "max commands per lun", host->cmd_per_lun); pos += sprintf(buffer + pos, "%24s %u\n", "max sg size per command", host->sg_tablesize); pos += sprintf(buffer + pos, "%24s %u\n", "max sectors per command", host->max_sectors); pos += sprintf(buffer + pos, "\n"); return pos;}/* scans the unsigned integer starting at ptr. * if result is <= max and only white space follows, return the result * otherwise set err */static void __attribute__ ((no_instrument_function))scan_numeric(char *ptr, __u32 max, __u32 *result, int *err){ __u32 temp; temp = simple_strtoul(ptr, &ptr, 0); if (temp > max || strspn(ptr, WHITE_SPACE) != strlen(ptr)) *err = -EINVAL; else *result = temp;}/* * executed only by command process. * Called only by scan_manage_stuff() */static int __attribute__ ((no_instrument_function))scan_force_stuff(char *ptr, struct iscsi_targetdata *targ_data, int result){ __u32 c_len, trace_info;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -