/* * Copyright(c) 2009 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope 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., * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * * Maintained at www.Open-FCoE.org */ #include "fcoeadm.h" /* #define TEST_HBAAPI_V1 */ #ifdef TEST_HBAAPI_V1 #define HBA_FCP_SCSI_ENTRY HBA_FCPSCSIENTRY #define HBA_FCP_TARGET_MAPPING HBA_FCPTARGETMAPPING #else #define HBA_FCP_SCSI_ENTRY HBA_FCPSCSIENTRYV2 #define HBA_FCP_TARGET_MAPPING HBA_FCPTARGETMAPPINGV2 #endif /* #define TEST_REPORT_LUNS */ /* #define TEST_READ_CAP_V1 */ /* #define TEST_DEV_SERIAL_NO */ /* Maximum number of HBA the display routines support */ #define MAX_HBA_COUNT 128 /* Define FC4 Type */ #define FC_TYPE_FCP 0x08 /* SCSI FCP */ /* Constant defined in fcoe_def.h of fcoe driver */ #define FCOE_WORD_TO_BYTE 4 /* Minimum byte size of the received inquiry data */ #define MIN_INQ_DATA_SIZE 36 struct sa_nameval { char *nv_name; u_int32_t nv_val; }; struct sa_nameval port_states[] = { { "Not Present", HBA_PORTSTATE_UNKNOWN }, { "Online", HBA_PORTSTATE_ONLINE }, { "Offline", HBA_PORTSTATE_OFFLINE }, { "Blocked", HBA_PORTSTATE_UNKNOWN }, { "Bypassed", HBA_PORTSTATE_BYPASSED }, { "Diagnostics", HBA_PORTSTATE_DIAGNOSTICS }, { "Linkdown", HBA_PORTSTATE_LINKDOWN }, { "Error", HBA_PORTSTATE_ERROR }, { "Loopback", HBA_PORTSTATE_LOOPBACK }, { "Deleted", HBA_PORTSTATE_UNKNOWN }, { NULL, 0 } }; /* * table of /sys port speed strings to HBA-API values. */ struct sa_nameval port_speeds[] = { { "10 Gbit", HBA_PORTSPEED_10GBIT }, { "2 Gbit", HBA_PORTSPEED_2GBIT }, { "1 Gbit", HBA_PORTSPEED_1GBIT }, { "Not Negotiated", HBA_PORTSPEED_NOT_NEGOTIATED }, { "Unknown", HBA_PORTSPEED_UNKNOWN }, { NULL, 0 } }; /** sa_enum_decode(buf, len, tp, val) * * @param buf buffer for result (may be used or not). * @param len size of buffer (at least 32 bytes recommended). * @param tp pointer to table of names and values, struct sa_nameval. * @param val value to be decoded into a name. * @returns pointer to name string. Unknown values are put into buffer in hex. */ static const char * sa_enum_decode(char *buf, size_t len, const struct sa_nameval *tp, u_int32_t val) { snprintf(buf, len, "Unknown"); for (; tp->nv_name != NULL; tp++) { if (tp->nv_val == val) { strncpy(buf, tp->nv_name, len); break; } } return buf; } static void sa_dump_wwn(void *Data, int Length, int Break) { unsigned char *pc = (unsigned char *)Data; int i; for (i = 1; i <= Length; i++) { printf("%02X", (int)*pc++); if ((Break != 0) && (!(i % Break))) printf(" "); } } /* * Make a printable NUL-terminated copy of the string. * The source buffer might not be NUL-terminated. */ static char * sa_strncpy_safe(char *dest, size_t len, const char *src, size_t src_len) { char *dp = dest; const char *sp = src; while (len-- > 1 && src_len-- > 0 && *sp != '\0') { *dp++ = isprint(*sp) ? *sp : (isspace(*sp) ? ' ' : '.'); sp++; } *dp = '\0'; /* * Take off trailing blanks. */ while (--dp >= dest && isspace(*dp)) *dp = '\0'; return dest; } /* * Read a line from the specified file in the specified directory * into the buffer. The file is opened and closed. * Any trailing white space is trimmed off. * This is useful for accessing /sys files. * Returns 0 or an error number. */ static int sa_sys_read_line(const char *dir, const char *file, char *buf, size_t len) { FILE *fp; char file_name[256]; char *cp; int rc = 0; snprintf(file_name, sizeof(file_name), "%s/%s", dir, file); fp = fopen(file_name, "r"); if (fp == NULL) rc = -1; else { cp = fgets(buf, len, fp); if (cp == NULL) { fprintf(stderr, "read error or empty file %s," " errno=0x%x\n", file_name, errno); rc = -1; } else { /* * Trim off trailing newline or other white space. */ cp = buf + strlen(buf); while (--cp >= buf && isspace(*cp)) *cp = '\0'; } fclose(fp); } return rc; } static int sa_sys_read_u32(const char *dir, const char *file, u_int32_t *vp) { char buf[256]; int rc; u_int32_t val; char *endptr; rc = sa_sys_read_line(dir, file, buf, sizeof(buf)); if (rc == 0) { val = strtoul(buf, &endptr, 0); if (*endptr != '\0') { fprintf(stderr, "parse error. file %s/%s line '%s'\n", dir, file, buf); rc = -1; } else *vp = val; } return rc; } static void show_wwn(unsigned char *pWwn) { sa_dump_wwn(pWwn, 8, 0); } static void show_hba_info(int hba_index, HBA_ADAPTERATTRIBUTES *hba_info, int flags) { printf("\n"); printf("HBA #%d\n", hba_index); printf(" Description: %s\n", hba_info->ModelDescription); printf(" Revision: %s\n", hba_info->HardwareVersion); printf(" Manufacturer: %s\n", hba_info->Manufacturer); printf(" Serial Number: %s\n", hba_info->SerialNumber); printf(" Driver: %s %s\n", hba_info->DriverName, hba_info->DriverVersion); printf(" Number of Ports: %d\n", hba_info->NumberOfPorts); } static void show_port_info(int hba_index, int lp_index, HBA_ADAPTERATTRIBUTES *hba_info, HBA_PORTATTRIBUTES *lp_info) { char buf[256]; int len = sizeof(buf); printf("\n Port #%d\n", lp_index); printf(" Symbolic Name: %s\n", lp_info->PortSymbolicName); printf(" OS Device Name: %s\n", lp_info->OSDeviceName); printf(" Node Name: 0x"); show_wwn(lp_info->NodeWWN.wwn); printf(" \n"); printf(" Port Name: 0x"); show_wwn(lp_info->PortWWN.wwn); printf(" \n"); printf(" FabricName: 0x"); show_wwn(lp_info->FabricName.wwn); printf(" \n"); sa_enum_decode(buf, len, port_speeds, lp_info->PortSpeed); printf(" Speed: %s\n", buf); sa_enum_decode(buf, len, port_speeds, lp_info->PortSupportedSpeed); printf(" Supported Speed: %s\n", buf); printf(" MaxFrameSize: %d\n", lp_info->PortMaxFrameSize); printf(" FC-ID (Port ID): 0x%06X\n", lp_info->PortFcId); sa_enum_decode(buf, sizeof(buf), port_states, lp_info->PortState); printf(" State: %s\n", buf); /* TODO: Display PortSupportedFc4Types and PortActiveFc4Types */ } static void show_target_info(int hba_index, int lp_index, int rp_index, HBA_ADAPTERATTRIBUTES *hba_info, HBA_PORTATTRIBUTES *rp_info) { char buf[256]; u_int32_t tgt_id; int rc; printf("Target #%d @ %s\n", rp_index, hba_info->NodeSymbolicName + 5); rc = sa_sys_read_line(rp_info->OSDeviceName, "roles", buf, sizeof(buf)); printf(" Roles: %s\n", buf); printf(" Node Name: 0x"); show_wwn(rp_info->NodeWWN.wwn); printf(" \n"); printf(" Port Name: 0x"); show_wwn(rp_info->PortWWN.wwn); printf(" \n"); rc = sa_sys_read_u32(rp_info->OSDeviceName, "scsi_target_id", &tgt_id); if (tgt_id != -1) printf(" Target ID: %d\n", tgt_id); printf(" MaxFrameSize: %d\n", rp_info->PortMaxFrameSize); printf(" OS Device Name: %s\n", strrchr(rp_info->OSDeviceName, '/') + 1); printf(" FC-ID (Port ID): 0x%06X\n", rp_info->PortFcId); sa_enum_decode(buf, sizeof(buf), port_states, rp_info->PortState); printf(" State: %s\n", buf); printf(" \n"); } static void show_sense_data(char *dev, char *sense, int slen) { printf("%s", dev); if (slen >= 3) printf(" Sense Key=0x%02x", sense[2]); if (slen >= 13) printf(" ASC=0x%02x", sense[12]); if (slen >= 14) printf(" ASCQ=0x%02x\n", sense[13]); printf("\n"); } #ifdef TEST_HBAAPI_V1 static HBA_STATUS get_inquiry_data_v1(HBA_HANDLE hba_handle, HBA_FCPSCSIENTRY *ep, char *inqbuf, size_t inqlen) { char sense[128]; HBA_UINT32 rlen; HBA_UINT32 slen; HBA_STATUS status; memset(inqbuf, 0, inqlen); memset(sense, 0, sizeof(sense)); rlen = (HBA_UINT32) inqlen; slen = (HBA_UINT32) sizeof(sense); status = HBA_SendScsiInquiry(hba_handle, ep->FcpId.PortWWN, ep->FcpId.FcpLun, 0, 0, inqbuf, rlen, sense, slen); if ((status != HBA_STATUS_OK) || (rlen < MIN_INQ_DATA_SIZE)) { fprintf(stderr, "%s: HBA_SendScsiInquiry failed, " "status=0x%x, rlen=%d\n", __func__, status, rlen); show_sense_data(ep->ScsiId.OSDeviceName, sense, slen); return HBA_STATUS_ERROR; } return HBA_STATUS_OK; } #else static HBA_STATUS get_inquiry_data_v2(HBA_HANDLE hba_handle, HBA_PORTATTRIBUTES *lp_info, HBA_FCPSCSIENTRYV2 *ep, char *inqbuf, size_t inqlen) { char sense[128]; HBA_UINT32 rlen; HBA_UINT32 slen; HBA_STATUS status; HBA_UINT8 sstat; memset(inqbuf, 0, inqlen); memset(sense, 0, sizeof(sense)); rlen = (HBA_UINT32) inqlen; slen = (HBA_UINT32) sizeof(sense); sstat = SCSI_ST_GOOD; status = HBA_ScsiInquiryV2(hba_handle, lp_info->PortWWN, ep->FcpId.PortWWN, ep->FcpId.FcpLun, 0, 0, inqbuf, &rlen, &sstat, sense, &slen); if ((status != HBA_STATUS_OK) || (sstat != SCSI_ST_GOOD) || (rlen < MIN_INQ_DATA_SIZE)) { fprintf(stderr, "%s: HBA_ScsiInquiryV2 failed, " "status=0x%x, sstat=0x%x, rlen=%d\n", __func__, status, sstat, rlen); if (sstat != SCSI_ST_GOOD) show_sense_data(ep->ScsiId.OSDeviceName, sense, slen); return HBA_STATUS_ERROR; } return HBA_STATUS_OK; } #endif #ifdef TEST_HBAAPI_V1 static HBA_STATUS get_device_capacity_v1(HBA_HANDLE hba_handle, HBA_FCPSCSIENTRY *ep, char *buf, size_t len) { char sense[128]; HBA_UINT32 rlen; HBA_UINT32 slen; HBA_STATUS status; int retry_count = 10; while (retry_count--) { memset(buf, 0, len); memset(sense, 0, sizeof(sense)); rlen = (HBA_UINT32)len; slen = (HBA_UINT32)sizeof(sense); status = HBA_SendReadCapacity(hba_handle, ep->FcpId.PortWWN, ep->FcpId.FcpLun, buf, rlen, sense, slen); if (status == HBA_STATUS_OK) return HBA_STATUS_OK; if (sense[2] == 0x06) continue; fprintf(stderr, "%s: HBA_SendReadCapacity failed, " "status=0x%x, slen=%d\n", __func__, status, slen); show_sense_data(ep->ScsiId.OSDeviceName, sense, slen); return HBA_STATUS_ERROR; } /* retry count exhausted */ return HBA_STATUS_ERROR; } #else static HBA_STATUS get_device_capacity_v2(HBA_HANDLE hba_handle, HBA_PORTATTRIBUTES *lp_info, HBA_FCPSCSIENTRYV2 *ep, char *buf, size_t len) { char sense[128]; HBA_UINT32 rlen; HBA_UINT32 slen; HBA_STATUS status; HBA_UINT8 sstat; int retry_count = 10; while (retry_count--) { memset(buf, 0, len); memset(sense, 0, sizeof(sense)); rlen = (HBA_UINT32)len; slen = (HBA_UINT32)sizeof(sense); sstat = SCSI_ST_GOOD; status = HBA_ScsiReadCapacityV2(hba_handle, lp_info->PortWWN, ep->FcpId.PortWWN, ep->FcpId.FcpLun, buf, &rlen, &sstat, sense, &slen); if ((status == HBA_STATUS_OK) && (sstat == SCSI_ST_GOOD)) return HBA_STATUS_OK; if ((sstat == SCSI_ST_CHECK) && (sense[2] == 0x06)) continue; fprintf(stderr, "%s: HBA_ScsiReadCapacityV2 failed, " "status=0x%x, sstat=0x%x, slen=%d\n", __func__, status, sstat, slen); if (sstat != SCSI_ST_GOOD) show_sense_data(ep->ScsiId.OSDeviceName, sense, slen); return HBA_STATUS_ERROR; } /* retry count exhausted */ return HBA_STATUS_ERROR; } #endif #ifdef TEST_DEV_SERIAL_NO static HBA_STATUS get_device_serial_number(HBA_HANDLE hba_handle, HBA_FCPSCSIENTRYV2 *ep, char *buf, size_t buflen) { struct scsi_inquiry_unit_sn *unit_sn; char rspbuf[256]; char sense[128]; HBA_UINT32 rlen; HBA_UINT32 slen; HBA_STATUS status; memset(rspbuf, 0, sizeof(rspbuf)); memset(sense, 0, sizeof(sense)); rlen = (HBA_UINT32) sizeof(rspbuf); slen = (HBA_UINT32) sizeof(sense); status = HBA_SendScsiInquiry(hba_handle, ep->FcpId.PortWWN, ep->FcpId.FcpLun, SCSI_INQF_EVPD, SCSI_INQP_UNIT_SN, rspbuf, rlen, sense, slen); if (status != HBA_STATUS_OK) { fprintf(stderr, "%s: inquiry page 0x80 failed, status=0x%x\n", __func__, status); show_sense_data(ep->ScsiId.OSDeviceName, sense, slen); return HBA_STATUS_ERROR; } unit_sn = (struct scsi_inquiry_unit_sn *)rspbuf; unit_sn->is_serial[unit_sn->is_page_len] = '\0'; sa_strncpy_safe(buf, buflen, (char *)unit_sn->is_serial, (size_t)unit_sn->is_page_len); return HBA_STATUS_OK; } #endif #ifdef TEST_REPORT_LUNS static void show_report_luns_data(char *rspbuf) { struct scsi_report_luns_resp *rp; int list_len; net64_t *lp; u_int64_t lun_id; rp = (struct scsi_report_luns_resp *)rspbuf; list_len = net32_get(&rp->rl_len); printf("\tTotal Number of LUNs=%lu\n", list_len/sizeof(u_int64_t)); for (lp = rp->rl_lun; list_len > 0; lp++, list_len -= sizeof(*lp)) { lun_id = net64_get(lp); if (!(lun_id & ((0xfc01ULL << 48) - 1))) printf("\tLUN %u\n", (u_int32_t)(lun_id >> 48)); else printf("\tLUN %lx\n", (u_int64_t)lun_id); } } static HBA_STATUS get_report_luns_data_v1(HBA_HANDLE hba_handle, HBA_FCPSCSIENTRYV2 *ep) { HBA_STATUS status; char rspbuf[512 * sizeof(u_int64_t)]; /* max 512 luns */ char sense[128]; HBA_UINT32 rlen; HBA_UINT32 slen; int retry_count = 10; while (retry_count--) { memset(rspbuf, 0, sizeof(rspbuf)); memset(sense, 0, sizeof(sense)); rlen = (HBA_UINT32) sizeof(rspbuf); slen = (HBA_UINT32) sizeof(sense); status = HBA_SendReportLUNs(hba_handle, ep->FcpId.PortWWN, rspbuf, rlen, sense, slen); if (status == HBA_STATUS_OK) { show_report_luns_data(rspbuf); return HBA_STATUS_OK; } if (sense[2] == 0x06) continue; fprintf(stderr, "%s: HBA_SendReportLUNs failed, " "status=0x%x, slen=%d\n", __func__, status, slen); show_sense_data(ep->ScsiId.OSDeviceName, sense, slen); return HBA_STATUS_ERROR; } /* retry count exhausted */ return HBA_STATUS_ERROR; } static HBA_STATUS get_report_luns_data_v2(HBA_HANDLE hba_handle, HBA_PORTATTRIBUTES *lp_info, HBA_FCPSCSIENTRYV2 *ep) { HBA_STATUS status; char rspbuf[512 * sizeof(u_int64_t)]; /* max 512 luns */ char sense[128]; HBA_UINT32 rlen; HBA_UINT32 slen; HBA_UINT8 sstat; int retry_count = 10; while (retry_count--) { memset(rspbuf, 0, sizeof(rspbuf)); memset(sense, 0, sizeof(sense)); rlen = (HBA_UINT32) sizeof(rspbuf); slen = (HBA_UINT32) sizeof(sense); sstat = SCSI_ST_GOOD; status = HBA_ScsiReportLUNsV2(hba_handle, lp_info->PortWWN, ep->FcpId.PortWWN, rspbuf, &rlen, &sstat, sense, &slen); if ((status == HBA_STATUS_OK) && (sstat == SCSI_ST_GOOD)) { show_report_luns_data(rspbuf); return HBA_STATUS_OK; } if ((sstat == SCSI_ST_CHECK) && (sense[2] == 0x06)) continue; fprintf(stderr, "%s: HBA_ScsiReportLUNsV2 failed, " "status=0x%x, sstat=0x%x, slen=%d\n", __func__, status, sstat, slen); if (sstat != SCSI_ST_GOOD) show_sense_data(ep->ScsiId.OSDeviceName, sense, slen); return HBA_STATUS_ERROR; } /* retry count exhausted */ return HBA_STATUS_ERROR; } #endif static void show_short_lun_info_header(void) { printf(" LUN ID Device Name Capacity " "Block Size Description\n"); printf(" ------ ----------- ---------- ---------- " "----------------------------\n"); } static void show_short_lun_info(HBA_FCP_SCSI_ENTRY *ep, char *inqbuf, struct scsi_rcap10_resp *rcap_resp) { struct scsi_inquiry_std *inq = (struct scsi_inquiry_std *)inqbuf; char vendor[10]; char model[20]; char capstr[32]; char rev[16]; u_int64_t cap; double cap_abbr; char *abbr; memset(vendor, 0, sizeof(vendor)); memset(model, 0, sizeof(model)); memset(capstr, 0, sizeof(capstr)); memset(rev, 0, sizeof(rev)); /* Get device capacity */ cap = (u_int64_t) net32_get(&rcap_resp->rc_block_len) * net32_get(&rcap_resp->rc_lba); cap_abbr = cap / (1024.0 * 1024.0); abbr = "MB"; if (cap_abbr >= 1024) { cap_abbr /= 1024.0; abbr = "GB"; } if (cap_abbr >= 1024) { cap_abbr /= 1024.0; abbr = "TB"; } if (cap_abbr >= 1024) { cap_abbr /= 1024.0; abbr = "PB"; } snprintf(capstr, sizeof(capstr), "%0.2f %s", cap_abbr, abbr); /* Get the device description */ sa_strncpy_safe(vendor, sizeof(vendor), inq->is_vendor_id, sizeof(inq->is_vendor_id)); sa_strncpy_safe(model, sizeof(model), inq->is_product, sizeof(inq->is_product)); sa_strncpy_safe(rev, sizeof(rev), inq->is_rev_level, sizeof(inq->is_rev_level)); /* Show the LUN info */ printf("%10d %-11s %10s %7d %s %s (rev %s)\n", ep->ScsiId.ScsiOSLun, ep->ScsiId.OSDeviceName, capstr, net32_get(&rcap_resp->rc_block_len), vendor, model, rev); } static void show_full_lun_info(HBA_HANDLE hba_handle, HBA_ADAPTERATTRIBUTES *hba_info, HBA_PORTATTRIBUTES *lp_info, HBA_PORTATTRIBUTES *rp_info, HBA_FCP_SCSI_ENTRY *ep, char *inqbuf, struct scsi_rcap10_resp *rcap_resp) { struct scsi_inquiry_std *inq = (struct scsi_inquiry_std *)inqbuf; char vendor[10]; char model[20]; char capstr[32]; char rev[16]; double cap_abbr; char *abbr; u_int64_t cap; u_int32_t tgt_id; u_int8_t pqual; #ifdef TEST_DEV_SERIAL_NO HBA_STATUS status; char serial_number[32]; #endif memset(vendor, 0, sizeof(vendor)); memset(model, 0, sizeof(model)); memset(capstr, 0, sizeof(capstr)); memset(rev, 0, sizeof(rev)); /* Get device description */ sa_strncpy_safe(vendor, sizeof(vendor), inq->is_vendor_id, sizeof(inq->is_vendor_id)); sa_strncpy_safe(model, sizeof(model), inq->is_product, sizeof(inq->is_product)); sa_strncpy_safe(rev, sizeof(rev), inq->is_rev_level, sizeof(inq->is_rev_level)); /* Get device capacity */ cap = (u_int64_t) net32_get(&rcap_resp->rc_block_len) * net32_get(&rcap_resp->rc_lba); cap_abbr = cap / (1024.0 * 1024.0); abbr = "MB"; if (cap_abbr >= 1024) { cap_abbr /= 1024.0; abbr = "GB"; } if (cap_abbr >= 1024) { cap_abbr /= 1024.0; abbr = "TB"; } if (cap_abbr >= 1024) { cap_abbr /= 1024.0; abbr = "PB"; } snprintf(capstr, sizeof(capstr), "%0.2f %s", cap_abbr, abbr); /* Get SCSI target ID */ sa_sys_read_u32(rp_info->OSDeviceName, "scsi_target_id", &tgt_id); /* Show lun info */ printf(" LUN #%d Information:\n", ep->ScsiId.ScsiOSLun); printf(" OS Device Name: %s\n", ep->ScsiId.OSDeviceName); printf(" Description: %s %s (rev %s)\n", vendor, model, rev); printf(" Ethernet Port FCID: 0x%06X\n", lp_info->PortFcId); printf(" Target FCID: 0x%06X\n", rp_info->PortFcId); if (tgt_id == -1) printf(" Target ID: (None)\n"); else printf(" Target ID: %u\n", tgt_id); printf(" LUN ID: %d\n", ep->ScsiId.ScsiOSLun); printf(" Capacity: %s\n", capstr); printf(" Capacity in Blocks: %d\n", net32_get(&rcap_resp->rc_lba)); printf(" Block Size: %d bytes\n", net32_get(&rcap_resp->rc_block_len)); pqual = inq->is_periph & SCSI_INQ_PQUAL_MASK; if (pqual == SCSI_PQUAL_ATT) printf(" Status: Attached\n"); else if (pqual == SCSI_PQUAL_DET) printf(" Status: Detached\n"); else if (pqual == SCSI_PQUAL_NC) printf(" Status: " "Not capable of attachment\n"); #ifdef TEST_DEV_SERIAL_NO /* Show the serial number of the device */ status = get_device_serial_number(hba_handle, ep, serial_number, sizeof(serial_number)); if (status == HBA_STATUS_OK) printf(" Serial Number: %s\n", serial_number); #endif printf("\n"); } /* Compare two LUN mappings for qsort */ static int lun_compare(const void *arg1, const void *arg2) { const HBA_FCP_SCSI_ENTRY *e1 = arg1; const HBA_FCP_SCSI_ENTRY *e2 = arg2; int diff; diff = e2->FcpId.FcId - e1->FcpId.FcId; if (diff == 0) diff = e1->ScsiId.ScsiOSLun - e2->ScsiId.ScsiOSLun; return diff; } static HBA_STATUS get_device_map(HBA_HANDLE hba_handle, HBA_PORTATTRIBUTES *lp_info, HBA_FCP_TARGET_MAPPING **tgtmap, u_int32_t *lun_count) { HBA_STATUS status; HBA_FCP_TARGET_MAPPING *map = NULL; HBA_FCP_SCSI_ENTRY *ep; u_int32_t limit; u_int32_t i; #define LUN_COUNT_START 8 /* number of LUNs to start with */ #define LUN_COUNT_INCR 4 /* excess to allocate */ /* * Get buffer large enough to retrieve all the mappings. * If they don't fit, increase the size of the buffer and retry. */ *lun_count = 0; limit = LUN_COUNT_START; for (;;) { i = (limit - 1) * sizeof(*ep) + sizeof(*map); map = malloc(i); if (map == NULL) { fprintf(stderr, "%s: malloc failed\n", __func__); return HBA_STATUS_ERROR; } memset((char *)map, 0, i); map->NumberOfEntries = limit; #ifdef TEST_HBAAPI_V1 status = HBA_GetFcpTargetMapping(hba_handle, map); #else status = HBA_GetFcpTargetMappingV2( hba_handle, lp_info->PortWWN, map); #endif if (map->NumberOfEntries > limit) { limit = map->NumberOfEntries + LUN_COUNT_INCR; free(map); continue; } if (status != HBA_STATUS_OK) { fprintf(stderr, "%s: HBA_GetFcpTargetMappingV2 failed\n", __func__); free(map); return HBA_STATUS_ERROR; } break; } if (map == NULL) { fprintf(stderr, "%s: map == NULL\n", __func__); return HBA_STATUS_ERROR; } if (map->NumberOfEntries > limit) { fprintf(stderr, "%s: map->NumberOfEntries=%d too big\n", __func__, map->NumberOfEntries); return HBA_STATUS_ERROR; } ep = map->entry; limit = map->NumberOfEntries; /* Sort the response by LUN number */ qsort(ep, limit, sizeof(*ep), lun_compare); *lun_count = limit; *tgtmap = map; return HBA_STATUS_OK; } static void scan_device_map(HBA_HANDLE hba_handle, HBA_ADAPTERATTRIBUTES *hba_info, HBA_PORTATTRIBUTES *lp_info, HBA_PORTATTRIBUTES *rp_info, struct opt_info *opt_info) { HBA_STATUS status; HBA_FCP_TARGET_MAPPING *map = NULL; u_int32_t limit; HBA_FCP_SCSI_ENTRY *ep; u_int32_t i; char *dev; char inqbuf[256]; struct scsi_rcap10_resp rcap_resp; int lun_count = 0; int print_header = 0; status = get_device_map(hba_handle, lp_info, &map, &limit); if (status != HBA_STATUS_OK) { fprintf(stderr, "%s: get_device_map() failed\n", __func__); return; } ep = map->entry; for (i = 0; i < limit; i++, ep++) { if (ep->FcpId.FcId != rp_info->PortFcId) continue; if (opt_info->l_flag && opt_info->l_fcid_present && opt_info->l_lun_id_present && ep->ScsiId.ScsiOSLun != opt_info->l_lun_id) continue; dev = ep->ScsiId.OSDeviceName; if (strstr(dev, "/dev/") == dev) dev += 5; /* Issue standard inquiry */ #ifdef TEST_HBAAPI_V1 status = get_inquiry_data_v1(hba_handle, ep, inqbuf, sizeof(inqbuf)); #else status = get_inquiry_data_v2(hba_handle, lp_info, ep, inqbuf, sizeof(inqbuf)); #endif if (status != HBA_STATUS_OK) continue; lun_count++; /* Issue read capacity */ #ifdef TEST_HBAAPI_V1 status = get_device_capacity_v1(hba_handle, ep, (char *)&rcap_resp, sizeof(rcap_resp)); #else status = get_device_capacity_v2(hba_handle, lp_info, ep, (char *)&rcap_resp, sizeof(rcap_resp)); #endif if (status != HBA_STATUS_OK) continue; if (opt_info->t_flag) { if (!print_header) { show_short_lun_info_header(); print_header = 1; } show_short_lun_info(ep, inqbuf, &rcap_resp); } else if (opt_info->l_flag) show_full_lun_info(hba_handle, hba_info, lp_info, rp_info, ep, inqbuf, &rcap_resp); #ifdef TEST_REPORT_LUNS if (i == 0) { /* only issue report luns to the first LUN */ #ifdef TEST_HBAAPI_V1 get_report_luns_data_v1(hba_handle, ep); #else get_report_luns_data_v2(hba_handle, lp_info, ep); #endif } #endif } free(map); printf("\n"); } static void show_port_stats_header(struct opt_info *opt_info) { printf("\n"); printf("%-7s interval: %-2d Err Inv " "IvTx Link Cntl Input Input Output Output\n", opt_info->ifname, opt_info->n_interval); printf("Seconds TxFrames TxBytes RxFrames RxBytes " "Frms CRC Byte Fail Reqs Requests MBytes " "Requests MBytes\n"); printf("------- --------- ------------ --------- -------------- " "---- ---- ---- ---- ---- --------- --------- " "--------- ---------\n"); } static void show_port_stats_in_row(HBA_INT64 start_time, HBA_PORTSTATISTICS *port_stats, HBA_FC4STATISTICS *port_fc4stats) { printf("%-7lld ", port_stats->SecondsSinceLastReset - start_time); printf("%-9lld ", port_stats->TxFrames); printf("%-12lld ", port_stats->TxWords * FCOE_WORD_TO_BYTE); printf("%-9lld ", port_stats->RxFrames); printf("%-14lld ", port_stats->RxWords * FCOE_WORD_TO_BYTE); printf("%-4lld ", port_stats->ErrorFrames); printf("%-4lld ", port_stats->InvalidCRCCount); printf("%-4lld ", port_stats->InvalidTxWordCount * FCOE_WORD_TO_BYTE); printf("%-4lld ", port_stats->LinkFailureCount); printf("%-4lld ", port_fc4stats->ControlRequests); printf("%-9lld ", port_fc4stats->InputRequests); printf("%-9lld ", port_fc4stats->InputMegabytes); printf("%-9lld ", port_fc4stats->OutputRequests); printf("%-9lld ", port_fc4stats->OutputMegabytes); printf("\n"); } void display_port_stats(struct opt_info *opt_info) { HBA_STATUS retval; HBA_UINT32 hba_cnt; HBA_HANDLE hba_handle; HBA_ADAPTERATTRIBUTES hba_attrs; HBA_PORTATTRIBUTES port_attrs; HBA_PORTSTATISTICS port_stats; HBA_FC4STATISTICS port_fc4stats; HBA_INT64 start_time = 0; char namebuf[1028]; int i = 0, found = 0; hba_cnt = HBA_GetNumberOfAdapters(); if (!hba_cnt) { fprintf(stderr, "No FCoE interfaces created.\n"); return; } for (i = 0; i < hba_cnt; i++) { retval = HBA_GetAdapterName(i, namebuf); if (retval != HBA_STATUS_OK) { fprintf(stderr, "Failure of HBA_GetAdapterName: %d\n", retval); continue; } hba_handle = HBA_OpenAdapter(namebuf); if (!hba_handle) { fprintf(stderr, "HBA_OpenAdapter failed\n"); perror("HBA_OpenAdapter"); continue; } retval = HBA_GetAdapterAttributes(hba_handle, &hba_attrs); if (retval != HBA_STATUS_OK) { fprintf(stderr, "HBA_GetAdapterAttributes failed, retval=%d\n", retval); perror("HBA_GetAdapterAttributes"); continue; } retval = HBA_GetAdapterPortAttributes( hba_handle, 0, &port_attrs); if (retval != HBA_STATUS_OK) { fprintf(stderr, "HBA_GetAdapterPortAttributes failed, " "status=%d\n", retval); continue; } if (strstr(port_attrs.PortSymbolicName, opt_info->ifname)) { found = 1; break; } } if (!found) { fprintf(stderr, "Cannot find attributes for %s\n", opt_info->ifname); return; } i = 0; while (1) { unsigned int secs_left; retval = HBA_GetPortStatistics(hba_handle, 0, &port_stats); if (retval != HBA_STATUS_OK && retval != HBA_STATUS_ERROR_NOT_SUPPORTED) { fprintf(stderr, "HBA_GetPortStatistics failed, status=%d\n", retval); break; } if (retval == HBA_STATUS_ERROR_NOT_SUPPORTED) { fprintf(stderr, "Port Statistics not supported by %s\n", opt_info->ifname); break; } if (!start_time) start_time = port_stats.SecondsSinceLastReset; retval = HBA_GetFC4Statistics(hba_handle, port_attrs.PortWWN, FC_TYPE_FCP, &port_fc4stats); if (retval != HBA_STATUS_OK && retval != HBA_STATUS_ERROR_NOT_SUPPORTED) { fprintf(stderr, "HBA_GetFC4Statistics failed, " "status=%d\n", retval); break; } if (retval == HBA_STATUS_ERROR_NOT_SUPPORTED) { fprintf(stderr, "Port FC4 Statistics not supported by %s\n", opt_info->ifname); break; } if (!(i % 52)) show_port_stats_header(opt_info); show_port_stats_in_row(start_time, &port_stats, &port_fc4stats); i++; /* wait for the requested time interval in seconds */ secs_left = opt_info->n_interval; do { secs_left = sleep(secs_left); } while (secs_left); } HBA_CloseAdapter(hba_handle); return; } static struct hba_name_table { char SerialNumber[64]; int index; } hba_name_table[MAX_HBA_COUNT]; static int find_hba_index(char *serial_number, int *hba_index) { int i, j; j = sizeof(hba_name_table[0].SerialNumber) - 1; for (i = 0; i < MAX_HBA_COUNT; i++) { if (hba_name_table[i].index == -1) { /* not found */ hba_name_table[i].index = i; /* TODO: change to sa_strncpy_safe */ strncpy(hba_name_table[i].SerialNumber, serial_number, j); *hba_index = i; return 1; /* print hba info */ } if (!strncmp(serial_number, hba_name_table[i].SerialNumber, j)) { *hba_index = hba_name_table[i].index; return 0; /* do not print hba info */ } } /* table full */ return -1; } void display_adapter_info(struct opt_info *opt_info) { HBA_STATUS retval; HBA_UINT32 hba_cnt; HBA_UINT32 lport_cnt_per_hba = 1; /* always one port per hba */ HBA_HANDLE hba_handle; HBA_ADAPTERATTRIBUTES hba_attrs; HBA_PORTATTRIBUTES port_attrs; char namebuf[1028]; int i, j, rc; int hba_index = -1; int lp_index = -1; for (i = 0; i < MAX_HBA_COUNT; i++) { hba_name_table[i].index = -1; memset(hba_name_table[i].SerialNumber, 0, sizeof(hba_name_table[i].SerialNumber)); } hba_cnt = HBA_GetNumberOfAdapters(); if (!hba_cnt) { fprintf(stderr, "No FCoE interfaces created.\n"); return; } for (i = 0; i < hba_cnt; i++) { retval = HBA_GetAdapterName(i, namebuf); if (retval != HBA_STATUS_OK) { fprintf(stderr, "Failure of HBA_GetAdapterName: %d\n", retval); continue; } hba_handle = HBA_OpenAdapter(namebuf); if (!hba_handle) { fprintf(stderr, "HBA_OpenAdapter failed\n"); perror("HBA_OpenAdapter"); continue; } retval = HBA_GetAdapterAttributes(hba_handle, &hba_attrs); if (retval != HBA_STATUS_OK) { fprintf(stderr, "HBA_GetAdapterAttributes failed, retval=%d\n", retval); perror("HBA_GetAdapterAttributes"); continue; } rc = find_hba_index(hba_attrs.SerialNumber, &hba_index); if (rc == -1) { fprintf(stderr, "Too many adapters. Maximum %d\n", MAX_HBA_COUNT); return; } else if (rc == 1) show_hba_info(hba_index, &hba_attrs, 0); for (j = 0; j < lport_cnt_per_hba; j++) { retval = HBA_GetAdapterPortAttributes( hba_handle, j, &port_attrs); if (retval != HBA_STATUS_OK) { fprintf(stderr, "HBA_GetAdapterPortAttributes failed, " "j=%d, status=%d\n", j, retval); continue; } lp_index++; if (opt_info->ifname && !strstr(port_attrs.PortSymbolicName, opt_info->ifname)) continue; show_port_info(hba_index, lp_index, &hba_attrs, &port_attrs); } HBA_CloseAdapter(hba_handle); } } void display_target_info(struct opt_info *opt_info) { HBA_STATUS retval; HBA_UINT32 hba_cnt; HBA_UINT32 lport_cnt_per_hba = 1; /* always one port per hba */ HBA_HANDLE hba_handle; HBA_ADAPTERATTRIBUTES hba_attrs; HBA_PORTATTRIBUTES port_attrs; HBA_PORTATTRIBUTES rport_attrs; char namebuf[1028]; int i, j, rc; int hba_index = -1; int lp_index = -1; int rp_index = -1; for (i = 0; i < MAX_HBA_COUNT; i++) { hba_name_table[i].index = -1; memset(hba_name_table[i].SerialNumber, 0, sizeof(hba_name_table[i].SerialNumber)); } hba_cnt = HBA_GetNumberOfAdapters(); if (!hba_cnt) { fprintf(stderr, "No FCoE interfaces created.\n"); return; } for (i = 0; i < hba_cnt; i++) { retval = HBA_GetAdapterName(i, namebuf); if (retval != HBA_STATUS_OK) { fprintf(stderr, "Failure of HBA_GetAdapterName: %d\n", retval); continue; } hba_handle = HBA_OpenAdapter(namebuf); if (!hba_handle) { fprintf(stderr, "HBA_OpenAdapter failed\n"); perror("HBA_OpenAdapter"); continue; } retval = HBA_GetAdapterAttributes(hba_handle, &hba_attrs); if (retval != HBA_STATUS_OK) { fprintf(stderr, "HBA_GetAdapterAttributes failed, retval=%d\n", retval); perror("HBA_GetAdapterAttributes"); continue; } rc = find_hba_index(hba_attrs.SerialNumber, &hba_index); if (rc == -1) { fprintf(stderr, "Too many adapters. Maximum %d\n", MAX_HBA_COUNT); return; } for (j = 0; j < lport_cnt_per_hba; j++) { retval = HBA_GetAdapterPortAttributes( hba_handle, j, &port_attrs); if (retval != HBA_STATUS_OK) { fprintf(stderr, "HBA_GetAdapterPortAttributes failed, " "j=%d, status=%d\n", j, retval); continue; } lp_index++; if (opt_info->ifname && !strstr(port_attrs.PortSymbolicName, opt_info->ifname)) continue; for (rp_index = 0; rp_index < port_attrs.NumberofDiscoveredPorts; rp_index++) { retval = HBA_GetDiscoveredPortAttributes( hba_handle, j, rp_index, &rport_attrs); if (retval != HBA_STATUS_OK) { fprintf(stderr, "HBA_GetDiscoveredPortAttributes " "failed, j=%d, for rp_index=%d, " "status=%d\n", j, rp_index, retval); continue; } /* * If -l option and fcid are specified in the * command, filter out the targets do not have * port ID equals to fcid. */ if (opt_info->l_flag && opt_info->l_fcid_present && rport_attrs.PortFcId != opt_info->l_fcid) continue; show_target_info(hba_index, lp_index, rp_index, &hba_attrs, &rport_attrs); scan_device_map(hba_handle, &hba_attrs, &port_attrs, &rport_attrs, opt_info); } } HBA_CloseAdapter(hba_handle); } }