2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/sysmacros.h>
2N/A#include <sys/scsi/impl/spc3_types.h>
2N/A#include <errno.h>
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <string.h>
2N/A#include <fcntl.h>
2N/A#include <values.h>
2N/A#include <unistd.h>
2N/A#include <pthread.h>
2N/A#include <devid.h>
2N/A#include <libgen.h>
2N/A#include <libdevinfo.h>
2N/A#include <scsi/libscsi.h>
2N/A#include "disklog.h"
2N/A#include "libdisklog.h"
2N/A
2N/Aboolean_t debug_mode = B_FALSE;
2N/A
2N/A/*
2N/A * Debug output function. Prints messages to stdout only if debug flag
2N/A * debug_mode is set to true.
2N/A */
2N/A/*PRINTFLIKE1*/
2N/Avoid
2N/Adprintf(const char *fmt, ...)
2N/A{
2N/A va_list ap;
2N/A
2N/A if (!debug_mode)
2N/A return;
2N/A
2N/A va_start(ap, fmt);
2N/A (void) vprintf(fmt, ap);
2N/A va_end(ap);
2N/A}
2N/A
2N/Astatic void
2N/Adl_fprintf(FILE *stream, const char *format, ...)
2N/A{
2N/A va_list args;
2N/A int ret;
2N/A
2N/A va_start(args, format);
2N/A ret = vfprintf(stream, format, args);
2N/A va_end(args);
2N/A
2N/A if (ret < 0) {
2N/A dprintf("Failed to write the file: %s\n", strerror(errno));
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_page_name_string(uint_t cmd, int pc, int spc, FILE *stream)
2N/A{
2N/A int i;
2N/A char *name_string;
2N/A
2N/A /*
2N/A * Define the command string. For INQUIRY command, use page_code
2N/A * to specify if evpd is set, if yes, the subpage_code stands for
2N/A * the vpd page number. For vendor specific commands, both the
2N/A * page_code and the subpage_code are zero, which means the command
2N/A * doesn't need them.
2N/A */
2N/A const struct page_strings {
2N/A uint_t cmd;
2N/A uint_t page_code;
2N/A uint_t subpage_code;
2N/A char *message;
2N/A } extended_page_strings[] = {
2N/A { SPC3_CMD_INQUIRY, 0x00, 0x00, "Standard INQUIRY Data" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x00, "Supported INQUIRY VPD Pages" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x80, "Unit Serial Number" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x83, "Device Identification" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x84,
2N/A "Software Interface Identification" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x85,
2N/A "Management Network Addresses" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x86, "Extended INQUIRY Data" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x87, "Mode Page Policy" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x88, "SCSI Ports" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x89, "ATA Information" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x8a, "Power Condition" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x8b, "Device Constituents" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x90,
2N/A "Protocol Specific Logical Unit Information" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0x91,
2N/A "Protocol Specific Port Information" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0xb0, "Block Limits VPD page" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0xb1,
2N/A "Block Device Characteristics VPD page" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0xb2, "Thin Provisioning VPD page" },
2N/A { SPC3_CMD_INQUIRY, 0x01, 0xb3, "Referrals VPD page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x00, 0x00, "Supported Log Pages" },
2N/A { SPC3_CMD_LOG_SENSE, 0x01, 0x00,
2N/A "Buffer Over-Run/Under-Run Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x02, 0x00, "Write Error Counter Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x03, 0x00, "Read Error Counter Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x04, 0x00,
2N/A "Read Reverse Error Counter Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x05, 0x00,
2N/A "Verify Error Counter Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x06, 0x00, "Non-Medium Error Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x07, 0x00, "Last N Error Events Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x08, 0x00, "Format Status Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x0b, 0x00,
2N/A "Last N Deferred Errors or Asynchronous Events Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x0d, 0x00, "Temperature Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x0c, 0x00, "Thin Provisioning Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x0e, 0x00,
2N/A "Start-Stop Cycle Counter Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x0f, 0x00, "Application Client Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x10, 0x00, "Self-Test Results Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x11, 0x00, "Solid State Media Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x15, 0x00,
2N/A "Background Scan Results Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x17, 0x00, "Non-Volatile Cache Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x18, 0x00,
2N/A "Protocol-Specific Port Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x19, 0x00,
2N/A "General Statistics and Performance Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x1a, 0x00,
2N/A "Power Condition Transitions Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x2f, 0x00,
2N/A "Informational Exceptions Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x37, 0x00, "Cache Log Page" },
2N/A { SPC3_CMD_LOG_SENSE, 0x3e, 0x00, "Factory Log Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x01, 0x00,
2N/A "Read-Write Error Recovery Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x02, 0x00,
2N/A "Disconnect-Reconnect Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x07, 0x00,
2N/A "Verify Error Recovery Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x08, 0x00, "Caching Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x0a, 0x00, "Control Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x0a, 0x01,
2N/A "Control Extension Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x10, 0x00, "XOR Control Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x13, 0x00, "Vendor Specific Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x14, 0x00,
2N/A "Enclosure Services Management Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x15, 0x00, "Extended Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x16, 0x00,
2N/A "Extended Device-Type Specific Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x18, 0x00,
2N/A "Protocol Specific Logical Unit Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x19, 0x00,
2N/A "Protocol Specific Port Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x1a, 0x00, "Power Condition Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x1c, 0x00,
2N/A "Informational Exceptions Control Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x1c, 0x01,
2N/A "Background Control Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x1c, 0x02,
2N/A "Thin Provisioning Mode Page" },
2N/A { SPC3_CMD_MODE_SENSE10, 0x3f, 0xff,
2N/A "Supported Mode Pages and Subpages" },
2N/A { SPC3_CMD_HITACHI_LOG_DUMP, 0x00, 0x00,
2N/A "HITACHI VIPER-A Log Dump Command" },
2N/A { SPC3_CMD_SEAGATE_LOG_DUMP, 0x00, 0x00,
2N/A "SEAGATE Drive Read Command" },
2N/A { 0xffff, 0xffff, 0xffff, NULL}
2N/A };
2N/A
2N/A for (i = 0; extended_page_strings[i].message != NULL; i++) {
2N/A if ((cmd == extended_page_strings[i].cmd) &&
2N/A (pc == extended_page_strings[i].page_code) &&
2N/A (spc == extended_page_strings[i].subpage_code)) {
2N/A name_string = (char *)extended_page_strings[i].message;
2N/A switch (cmd) {
2N/A case SPC3_CMD_INQUIRY:
2N/A dl_fprintf(stream,
2N/A "---- %s(evpd-%02xh,pc-%02xh) ----\n",
2N/A name_string, (uint8_t)pc, (uint8_t)spc);
2N/A return;
2N/A case SPC3_CMD_LOG_SENSE:
2N/A dl_fprintf(stream,
2N/A "---- %s(pc-%02xh) ----\n",
2N/A name_string, (uint8_t)pc);
2N/A return;
2N/A case SPC3_CMD_MODE_SENSE10:
2N/A dl_fprintf(stream,
2N/A "---- %s(pc-%02xh,spc-%02xh) ----\n",
2N/A name_string, (uint8_t)pc, (uint8_t)spc);
2N/A return;
2N/A default:
2N/A dl_fprintf(stream, "---- %s ----\n",
2N/A name_string);
2N/A return;
2N/A }
2N/A }
2N/A }
2N/A
2N/A switch (cmd) {
2N/A case SPC3_CMD_INQUIRY:
2N/A dl_fprintf(stream,
2N/A "---- Vendor Specific INQUIRY Data(evpd-%02xh,pc-%02xh) "
2N/A "----\n", (uint8_t)pc, (uint8_t)spc);
2N/A return;
2N/A case SPC3_CMD_LOG_SENSE:
2N/A dl_fprintf(stream,
2N/A "---- Vendor Specific Log Page(pc-%02xh) ----\n",
2N/A (uint8_t)pc);
2N/A return;
2N/A case SPC3_CMD_MODE_SENSE10:
2N/A dl_fprintf(stream,
2N/A "---- Vendor Specific Mode Page(pc-%02xh,spc-%02xh) ----\n",
2N/A (uint8_t)pc, (uint8_t)spc);
2N/A return;
2N/A default:
2N/A dl_fprintf(stream,
2N/A "---- Unknown command(pc-%02xh,spc-%02xh) ----\n",
2N/A (uint8_t)pc, (uint8_t)spc);
2N/A return;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_buf(char *buf, int len, FILE *stream)
2N/A{
2N/A int i, j;
2N/A
2N/A for (i = 0; i < len; i += 16) {
2N/A dl_fprintf(stream, "%04x: ", i);
2N/A for (j = i; j < i + 16 && j < len; j++)
2N/A dl_fprintf(stream, "%02x ", (uint8_t)buf[j]);
2N/A dl_fprintf(stream, "\n");
2N/A }
2N/A
2N/A dl_fprintf(stream, "\n");
2N/A}
2N/A
2N/Astatic void
2N/Aprint_hex_value(const char *value_buf, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i++)
2N/A dl_fprintf(stream, "%02x", (uint8_t)value_buf[i]);
2N/A}
2N/A
2N/Astatic void
2N/Aprint_decimal_value(const char *value_buf, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A uint64_t ull = (uint8_t)value_buf[0];
2N/A
2N/A for (i = 1; i < len; i++) {
2N/A ull <<= BITSPERBYTE;
2N/A ull = (uint8_t)value_buf[i] | ull;
2N/A }
2N/A
2N/A dl_fprintf(stream, "%llu", ull);
2N/A}
2N/A
2N/Astatic int
2N/Aactual_inq_len(boolean_t evpd, char *inq_data, int len)
2N/A{
2N/A spc3_inquiry_vpd_header_t *hp;
2N/A
2N/A hp = (spc3_inquiry_vpd_header_t *)inq_data;
2N/A
2N/A if (evpd == B_FALSE)
2N/A return (MIN(len, sizeof (struct spc3_inquiry_data)));
2N/A else
2N/A return (MIN(len, (SCSI_READ16(&(hp->ivh_page_len)) +
2N/A sizeof (struct spc3_inquiry_vpd_header))));
2N/A}
2N/A
2N/Astatic boolean_t
2N/Ais_vpd_page_supported(int pc, char *vpd_pages, int len)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i++)
2N/A if (pc == (uint8_t)vpd_pages[i])
2N/A return (B_TRUE);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Astatic void
2N/Aprint_inq_supported_pages(char *vpd_pages, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i++)
2N/A dl_fprintf(stream, "%02xh ", (uint8_t)vpd_pages[i]);
2N/A
2N/A dl_fprintf(stream, "\n\n");
2N/A}
2N/A
2N/Astatic void
2N/Aparse_inq_all(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A char *vpd_pages, int len, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int i;
2N/A
2N/A disklog_send_inquiry(hp, tp, B_FALSE, 0, stream, flags);
2N/A
2N/A for (i = 0; i < len; i++)
2N/A if ((uint8_t)vpd_pages[i] != 0)
2N/A disklog_send_inquiry(
2N/A hp, tp, B_TRUE, (uint8_t)vpd_pages[i], stream,
2N/A flags);
2N/A}
2N/A
2N/Astatic void
2N/Aparse_inq_basic_pages(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A char *vpd_pages, int len, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int i;
2N/A const spc3_inquiry_page_code_t basic_inquiry_vpd_pages[] = {
2N/A SPC3_INQUIRY_PC_UNIT_SERIAL_NUMBER,
2N/A SPC3_INQUIRY_PC_DEV_ID
2N/A };
2N/A
2N/A disklog_send_inquiry(hp, tp, B_FALSE, 0, stream, flags);
2N/A for (i = 0; i < sizeof (basic_inquiry_vpd_pages) /
2N/A sizeof (spc3_inquiry_page_code_t); i++)
2N/A if ((is_vpd_page_supported(
2N/A basic_inquiry_vpd_pages[i], vpd_pages, len)) == B_TRUE)
2N/A disklog_send_inquiry(
2N/A hp, tp, B_TRUE, basic_inquiry_vpd_pages[i], stream,
2N/A flags);
2N/A}
2N/A
2N/Astatic void
2N/Aprint_inq_std(char *inq_std_data, FILE *stream)
2N/A{
2N/A spc3_inquiry_data_t *dp;
2N/A
2N/A dp = (spc3_inquiry_data_t *)inq_std_data;
2N/A dl_fprintf(stream,
2N/A "PERIPHERAL DEVICE TYPE: %d PERIPHERAL QUALIFIER : %d\n"
2N/A "RMB : %d VERSION : %d RESPONSE DATA FORMAT : %d\n"
2N/A "HISUP : %d NORMACA : %d ADDITIONAL LENGTH : %d\n"
2N/A "PROTECT: %d 3PC : %d TPGS : %d ACC: %d\n"
2N/A "SCCS : %d ADDR16 : %d MCHANGER: %d MULTIP: %d\n"
2N/A "VS_6_5 : %d ENCSERV : %d BQUE : %d VS_7_0: %d\n"
2N/A "CMDQUE : %d LINKED : %d SYNC : %d WBUS16: %d\n"
2N/A "VENDOR_ID : %.8s\n"
2N/A "PRODUCT_ID : %.16s\n"
2N/A "PRODUCT_REVISION : %.4s\n"
2N/A "IUS : %d QAS : %d CLOCKING: %d\n"
2N/A "VERSION_DESCRIPTORS : %d\n\n",
2N/A dp->id_peripheral_device_type, dp->id_peripheral_qualifier,
2N/A dp->id_rmb, dp->id_version, dp->id_response_data_format,
2N/A dp->id_hisup, dp->id_naca, dp->additional_length, dp->id_protect,
2N/A dp->id_3pc, dp->id_tpgs, dp->id_acc, dp->id_sccs, dp->id_addr16,
2N/A dp->id_mchanger, dp->id_multip, dp->id_vs_6_5, dp->id_enc_serv,
2N/A dp->id_b_que, dp->id_vs_7_0, dp->id_cmd_que, dp->id_linked,
2N/A dp->id_sync, dp->id_wbus16, dp->id_vendor_id, dp->id_product_id,
2N/A dp->id_product_revision, dp->id_ius, dp->id_qas, dp->id_clocking,
2N/A SCSI_READ16(&(dp->id_version_descriptors)));
2N/A}
2N/A
2N/Astatic void
2N/Aprint_inq_serialno(char *inq_serial_data, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A
2N/A dl_fprintf(stream, "SERIAL NUMBER: ");
2N/A
2N/A for (i = sizeof (struct spc3_inquiry_vpd_header); i < len; i++)
2N/A dl_fprintf(stream, "%c", inq_serial_data[i]);
2N/A
2N/A dl_fprintf(stream, "\n\n");
2N/A}
2N/A
2N/Astatic void
2N/Aprint_inq_page83(char *inq_page83_data, int len, FILE *stream)
2N/A{
2N/A int i, j;
2N/A int desc_len;
2N/A char *protocol_id = "RESERVED";
2N/A char *code_set = "RESERVED ";
2N/A char *id_type = "RESERVED";
2N/A const struct vpd_protocol_id {
2N/A int pid;
2N/A char *id_str;
2N/A } extended_vpd_protocol_id[] = {
2N/A { SPC3_IVDI_PI_FIBRE, "FIBRE CHANNEL" },
2N/A { SPC3_IVDI_PI_SCSI, "PARALLEL SCSI" },
2N/A { SPC3_IVDI_PI_SSA, "SSA" },
2N/A { SPC3_IVDI_PI_IEEE, "IEEE 1394" },
2N/A { SPC3_IVDI_PI_SRP, "SCSI REMOTE DIRECT MEMORY ACCESS PROTOCOL" },
2N/A { SPC3_IVDI_PI_ISCSI, "ISCSI" },
2N/A { SPC3_IVDI_PI_SAS, "SAS SERIAL SCSI PROTOCOL" },
2N/A { SPC3_IVDI_PI_ADT, "AUTO/DRIVE INTERFACE TRANSPORT PROTOCOL" },
2N/A { SPC3_IVDI_PI_ATA, "ATA/ATAPI" },
2N/A { SPC3_IVDI_PI_NONE, "NO SPECIFIC PROTOCOL" },
2N/A { 0xff, NULL }
2N/A };
2N/A const struct vpd_code_set {
2N/A int vpd_code;
2N/A char *vpd_cs_str;
2N/A } extended_vpd_code_set[] = {
2N/A { SPC3_IVDI_CS_BINARY, "BINARY " },
2N/A { SPC3_IVDI_CS_ASCII, "ASCII " },
2N/A { SPC3_IVDI_CS_UTF, "UTF-8 " },
2N/A { 0xff, NULL }
2N/A };
2N/A const struct vpd_id_type {
2N/A int vpd_code;
2N/A char *vpd_id_type_str;
2N/A } extended_vpd_id_type[] = {
2N/A { SPC3_IVDI_TYPE_VENDOR_SPECIFIC, "VENDOR SPECIFIC" },
2N/A { SPC3_IVDI_TYPE_T10, "T10 VENDOR ID BASED" },
2N/A { SPC3_IVDI_TYPE_EUI64, "EUI-64 BASED" },
2N/A { SPC3_IVDI_TYPE_NAA, "NAA" },
2N/A { SPC3_IVDI_TYPE_TGT_PORT, "RELATIVE TARGET PORT IDENTIFIER" },
2N/A { SPC3_IVDI_TYPE_TGT_PORT_GROUP, "TARGET PORT GROUP" },
2N/A { SPC3_IVDI_TYPE_LU_GROUP, "LOGICAL UNIT GROUP" },
2N/A { SPC3_IVDI_TYPE_MD5_LU, "MD5 LOGICAL UNIT IDENTIFIER" },
2N/A { SPC3_IVDI_TYPE_SCSI_NAME_STRING, "SCSI NAME STRING" },
2N/A { 0xff, NULL }
2N/A };
2N/A const char *str_association[] = {
2N/A "ASSOCIATED WITH THE ADDRESSED LU",
2N/A "ASSOCIATED WITH THE TARGET PORT THAT RECEIVED THE REQUEST",
2N/A "ASSOCIATED WITH THE SCSI TARGET DEVICE CONTAINING THE LU",
2N/A "RESERVED"
2N/A };
2N/A spc3_inquiry_vpd_id_header_t *dp;
2N/A
2N/A i = sizeof (struct spc3_inquiry_vpd_header);
2N/A
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_inquiry_vpd_id_header) > len) {
2N/A dl_fprintf(stream, "INQUIRY page83 data invalid\n");
2N/A break;
2N/A }
2N/A
2N/A dp = (spc3_inquiry_vpd_id_header_t *)(&inq_page83_data[i]);
2N/A desc_len = sizeof (struct spc3_inquiry_vpd_id_header) +
2N/A dp->ivih_idlen;
2N/A
2N/A if (i + desc_len > len) {
2N/A dl_fprintf(stream, "INQUIRY page83 data invalid\n");
2N/A break;
2N/A }
2N/A
2N/A if (dp->ivih_piv == B_TRUE && (dp->ivih_association ==
2N/A SPC3_IVID_ASS_TGTPORT || dp->ivih_association ==
2N/A SPC3_IVID_ASS_TGTDEV)) {
2N/A for (j = 0; extended_vpd_protocol_id[j].id_str != NULL;
2N/A j++) {
2N/A if (extended_vpd_protocol_id[j].pid ==
2N/A dp->ivih_protocol_id) {
2N/A protocol_id =
2N/A extended_vpd_protocol_id[j].id_str;
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A
2N/A for (j = 0; extended_vpd_code_set[j].vpd_cs_str != NULL; j++) {
2N/A if (extended_vpd_code_set[j].vpd_code ==
2N/A dp->ivih_code_set) {
2N/A code_set = extended_vpd_code_set[j].vpd_cs_str;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A for (j = 0; extended_vpd_id_type[j].vpd_id_type_str != NULL;
2N/A j++) {
2N/A if (extended_vpd_id_type[j].vpd_code ==
2N/A dp->ivih_id_type) {
2N/A id_type =
2N/A extended_vpd_id_type[j].vpd_id_type_str;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A dl_fprintf(stream,
2N/A "CODE SET : %s\nPROTOCOL ID: %s\n"
2N/A "ID TYPE : %s\nASSOCIATION: %s\n"
2N/A "PIV : %d ID LEN : %d\n",
2N/A code_set, protocol_id, id_type,
2N/A str_association[dp->ivih_association], dp->ivih_piv,
2N/A dp->ivih_idlen);
2N/A
2N/A dl_fprintf(stream, "IDENTIFIER : 0x");
2N/A print_hex_value((char *)&inq_page83_data[i +
2N/A sizeof (struct spc3_inquiry_vpd_id_header)], dp->ivih_idlen,
2N/A stream);
2N/A dl_fprintf(stream, "\n\n");
2N/A
2N/A i += desc_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_inq_ext(char *inq_ext_data, int len, FILE *stream)
2N/A{
2N/A spc3_inquiry_vpd_ei_data_t *dp;
2N/A
2N/A dp = (spc3_inquiry_vpd_ei_data_t *)inq_ext_data;
2N/A
2N/A if (len < sizeof (struct spc3_inquiry_vpd_ei_data)) {
2N/A dl_fprintf(stream, "Extended INQUIRY data invalid\n");
2N/A return;
2N/A }
2N/A
2N/A dl_fprintf(stream,
2N/A "REF_CHK : %d APP_CHK: %d GRD_CHK: %d RTO : %d\n"
2N/A "SIMPSUP : %d ORDSUP : %d HEADSUP: %d PRIOR_SUP: %d\n"
2N/A "GROUP_SUP: %d V_SUP : %d NV_SUP : %d\n\n",
2N/A dp->ived_ref_chk, dp->ived_app_chk, dp->ived_grd_chk,
2N/A dp->ived_rto, dp->ived_simpsup, dp->ived_ordsup,
2N/A dp->ived_headsup, dp->ived_prior_sup, dp->ived_group_sup,
2N/A dp->ived_v_sup, dp->ived_nv_sup);
2N/A}
2N/A
2N/Astatic void
2N/Aprint_inq_mode_policy(char *inq_mp_data, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A spc3_inquiry_vpd_mppd_data_t *dp;
2N/A
2N/A const char *policy_string[] = {
2N/A "SHARED",
2N/A "PER TARGET PORT",
2N/A "OBSOLETE",
2N/A "PER I_T NEXUS"
2N/A };
2N/A
2N/A i = sizeof (struct spc3_inquiry_vpd_header);
2N/A
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_inquiry_vpd_mppd_data) > len) {
2N/A dl_fprintf(stream,
2N/A "INQUIRY mode page policy data invalid\n");
2N/A break;
2N/A }
2N/A
2N/A dp = (spc3_inquiry_vpd_mppd_data_t *)(&inq_mp_data[i]);
2N/A dl_fprintf(stream,
2N/A "POLICY PAGE CODE: 0x%02x POLICY SUBPAGE CODE: 0x%02x\n"
2N/A "MLUS : %d MODE POLICY CODE : %s\n\n",
2N/A dp->ivmd_policy_page_code, dp->ivmd_policy_subapge_code,
2N/A dp->ivmd_mlus, policy_string[dp->ivmd_mode_page_policy]);
2N/A i += sizeof (struct spc3_inquiry_vpd_mppd_data);
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Aactual_log_len(char *log_data, int len)
2N/A{
2N/A spc3_log_page_header_t *hp;
2N/A
2N/A hp = (spc3_log_page_header_t *)log_data;
2N/A
2N/A return (MIN(len, sizeof (struct spc3_log_page_header) +
2N/A SCSI_READ16(&(hp->lph_plen))));
2N/A}
2N/A
2N/Astatic boolean_t
2N/Ais_log_page_supported(int pc, char *log_pages, int len)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i++)
2N/A if (pc == (uint8_t)log_pages[i])
2N/A return (B_TRUE);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_supported_pages(char *log_pages, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i++)
2N/A dl_fprintf(stream, "%02xh ", (uint8_t)log_pages[i]);
2N/A
2N/A dl_fprintf(stream, "\n\n");
2N/A}
2N/A
2N/Astatic void
2N/Aparse_log_all(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A char *log_pages, int len, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i ++)
2N/A if (log_pages[i] != SPC3_LOG_PC_ALL)
2N/A disklog_send_log_sense(hp, tp,
2N/A log_pages[i], stream, flags);
2N/A}
2N/A
2N/Astatic void
2N/Aparse_log_basic_pages(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A char *log_pages, int len, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int i;
2N/A const spc3_log_page_code_t basic_log_pages[] = {
2N/A SPC3_LOG_PC_WRITE_ERR,
2N/A SPC3_LOG_PC_READ_ERR,
2N/A SPC3_LOG_PC_READ_REV_ERR,
2N/A SPC3_LOG_PC_VERIFY_ERR,
2N/A SPC3_LOG_PC_NON_MEDIUM,
2N/A SPC3_LOG_PC_TEMPERATURE,
2N/A SPC3_LOG_PC_START_STOP,
2N/A SPC3_LOG_PC_SELF_TEST
2N/A };
2N/A
2N/A for (i = 0; i < sizeof (basic_log_pages) /
2N/A sizeof (spc3_log_page_code_t); i++)
2N/A if ((is_log_page_supported(basic_log_pages[i], log_pages, len))
2N/A == B_TRUE)
2N/A disklog_send_log_sense(
2N/A hp, tp, basic_log_pages[i], stream, flags);
2N/A}
2N/A
2N/A#define PRINT_LOG_PARAM_HEADER(hp) \
2N/A dl_fprintf(stream, \
2N/A "LP : %d LBIN: %d TMC: %d ETC : %d\n" \
2N/A "TSD: %d DS : %d DU : %d PARAM LEN: %d\n", \
2N/A (hp)->lph_lp, (hp)->lph_lbin, (hp)->lph_tmc, (hp)->lph_etc, \
2N/A (hp)->lph_tsd, (hp)->lph_ds, (hp)->lph_du, (hp)->lph_prlen);
2N/A
2N/Astatic void
2N/Aprint_log_error_counter(char *log_error_counter_data, int len, FILE *stream)
2N/A{
2N/A int i, j;
2N/A int code, param_len;
2N/A char *code_string = "RESERVED";
2N/A spc3_log_params_header_t *dp;
2N/A const struct log_err_code_str {
2N/A int param_code;
2N/A char *code_str;
2N/A } extended_log_err_code_str[] = {
2N/A { SPC3_LOG_ERR_PC_NDELAY,
2N/A "ERRORS CORRECTED WITHOUT SUBSTANTIAL DELAY" },
2N/A { SPC3_LOG_ERR_PC_DELAY, "ERRORS CORRECTED WITH POSSIBLE DELAYS" },
2N/A { SPC3_LOG_ERR_PC_TOTAL, "TOTAL REWRITES OR REREADS" },
2N/A { SPC3_LOG_ERR_PC_TOTAL_ERR, "TOTAL ERRORS CORRECTED" },
2N/A { SPC3_LOG_ERR_PC_TOTAL_TIMES,
2N/A "TOTAL TIMES CORRECTION ALGORITHM PROCESSED" },
2N/A { SPC3_LOG_ERR_PC_TOTAL_BYTES, "TOTAL BYTES PROCESSED" },
2N/A { SPC3_LOG_ERR_PC_TOTAL_UNCORRECTED_ERR,
2N/A "TOTAL UNCORRECTED ERRORS" },
2N/A { DL_LOG_PC_ERR_HITACHI_TR, "HITACHI TRACK FOLLWING ERRORS" },
2N/A { DL_LOG_PC_ERR_HITACHI_POS, "HITACHI POSITIONING ERRORS" },
2N/A { 0xfffff, NULL }
2N/A };
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_log_params_header) > len) {
2N/A dl_fprintf(stream, "Log error page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A dp = (spc3_log_params_header_t *)(&log_error_counter_data[i]);
2N/A param_len = sizeof (struct spc3_log_params_header) +
2N/A dp->lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log error page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A code = SCSI_READ16(dp);
2N/A if (code > SPC3_LOG_ERR_PC_RSVD_END)
2N/A code_string = "VENDOR SPECIFIC";
2N/A for (j = 0; extended_log_err_code_str[j].code_str != NULL;
2N/A j++) {
2N/A if (extended_log_err_code_str[j].param_code == code) {
2N/A code_string =
2N/A extended_log_err_code_str[j].code_str;
2N/A break;
2N/A }
2N/A }
2N/A dl_fprintf(stream, "PARAM CODE : %04xh (%s)\n",
2N/A code, code_string);
2N/A PRINT_LOG_PARAM_HEADER(dp);
2N/A dl_fprintf(stream, "PARAM VALUE : ");
2N/A print_decimal_value(&log_error_counter_data[i +
2N/A sizeof (struct spc3_log_params_header)], dp->lph_prlen,
2N/A stream);
2N/A dl_fprintf(stream, "\n\n");
2N/A
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_non_medium(char *log_non_medium_data, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A int code, param_len;
2N/A char *code_string = "RESERVED";
2N/A spc3_log_params_header_t *dp;
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_log_params_header) > len) {
2N/A dl_fprintf(stream, "Log non medium page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A dp = (spc3_log_params_header_t *)(&log_non_medium_data[i]);
2N/A param_len = sizeof (struct spc3_log_params_header) +
2N/A dp->lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log non medium page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A code = SCSI_READ16(dp);
2N/A if (code == SPC3_LOG_NM_PC_ERR_CNT)
2N/A code_string = "Non Medium ERR COUNT";
2N/A else if (code > SPC3_LOG_NM_PC_ERR_CNT_RSVD_END)
2N/A code_string = "VENDER SPECIFIC ERR COUNT";
2N/A dl_fprintf(stream, "PARAM CODE : %04xh (%s)\n",
2N/A code, code_string);
2N/A PRINT_LOG_PARAM_HEADER(dp);
2N/A dl_fprintf(stream, "PARAM VALUE : ");
2N/A print_decimal_value(&log_non_medium_data[i +
2N/A sizeof (struct spc3_log_params_header)], dp->lph_prlen,
2N/A stream);
2N/A dl_fprintf(stream, "\n\n");
2N/A
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_temperature(char *log_temperature_data, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A int code, param_len;
2N/A spc3_log_params_header_t *hp;
2N/A spc3_log_params_temperature_t *dp;
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A dp = (spc3_log_params_temperature_t *)(&log_temperature_data[i]);
2N/A
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_log_params_header) > len) {
2N/A dl_fprintf(stream, "Log temperature page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A hp = (spc3_log_params_header_t *)(&log_temperature_data[i]);
2N/A param_len = sizeof (struct spc3_log_params_header) +
2N/A hp->lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log temperature page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A code = SCSI_READ16(&(hp->lph_param_code));
2N/A dl_fprintf(stream, "PARAM CODE : %04xh\n", code);
2N/A PRINT_LOG_PARAM_HEADER(hp);
2N/A
2N/A if (code == SPC3_LOG_PTPC_TEMPERATURE)
2N/A dl_fprintf(stream,
2N/A "CURRENT TEMPERATURE : %d C\n\n",
2N/A dp->lpt_t);
2N/A else if (code == SPC3_LOG_PTPC_REF_TEMPERATURE)
2N/A dl_fprintf(stream,
2N/A "REFERENCE TEMPERATURE : %d C\n\n",
2N/A dp->lpt_rt);
2N/A else
2N/A dl_fprintf(stream, "UNDEFINED PARAM CODE\n\n");
2N/A
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_start_stop(char *log_start_stop_data, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A int code, param_len;
2N/A spc3_log_params_header_t *hp;
2N/A spc3_log_params_start_stop_t *dp;
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A dp = (spc3_log_params_start_stop_t *)(&log_start_stop_data[i]);
2N/A
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_log_params_header) > len) {
2N/A dl_fprintf(stream, "Log start stop page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A hp = (spc3_log_params_header_t *)(&log_start_stop_data[i]);
2N/A param_len = sizeof (struct spc3_log_params_header) +
2N/A hp->lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log start stop page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A code = SCSI_READ16(&(hp->lph_param_code));
2N/A dl_fprintf(stream, "PARAM CODE : %04x\n", code);
2N/A PRINT_LOG_PARAM_HEADER(hp);
2N/A
2N/A switch (code) {
2N/A case SPC3_LOG_PSS_PC_DATE_OF_MANUFACTURE:
2N/A dl_fprintf(stream,
2N/A "YEAR OF MANUFACTURE : %.4s\n"
2N/A "WEEK OF MANUFACTURE : %.2s\n\n",
2N/A dp->lpss_year1, dp->lpss_week1);
2N/A break;
2N/A case SPC3_LOG_PSS_PC_DATE_OF_ACCOUNTING:
2N/A dl_fprintf(stream,
2N/A "ACCOUNTING DATE YEAR : %.4s\n"
2N/A "ACCOUNTING DATE WEEK : %.2s\n\n",
2N/A dp->lpss_year2, dp->lpss_week2);
2N/A break;
2N/A case SPC3_LOG_PSS_PC_CYCLE_SPECIFIED:
2N/A dl_fprintf(stream,
2N/A "SPECIFIED CYCLE COUNT OVER DEVICE LIFETIME : "
2N/A "%d\n\n", SCSI_READ32(&(dp->lpss_cc)));
2N/A break;
2N/A case SPC3_LOG_PSS_PC_CYCLE_ACCUMULATED:
2N/A dl_fprintf(stream,
2N/A "SPECIFIED CYCLE COUNT OVER DEVICE LIFETIME : "
2N/A "%d\n\n", SCSI_READ32(&(dp->lpss_ac)));
2N/A break;
2N/A default:
2N/A dl_fprintf(stream, "UNDEFINED PARAM CODE\n\n");
2N/A break;
2N/A }
2N/A
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_self_test(char *log_self_test_data, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A int code, param_len;
2N/A spc3_log_params_self_test_t *dp;
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_log_params_header) > len) {
2N/A dl_fprintf(stream, "Log self test page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A dp = (spc3_log_params_self_test_t *)(&log_self_test_data[i]);
2N/A param_len = sizeof (struct spc3_log_params_header) +
2N/A dp->lpst_prh.lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log self test page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A code = SCSI_READ16(&(dp->lpst_prh.lph_param_code));
2N/A if (code < SPC3_LOG_PST_PC_BEGIN || code > SPC3_LOG_PST_PC_END)
2N/A break;
2N/A
2N/A dl_fprintf(stream, "PARAM CODE : %04xh\n", code);
2N/A PRINT_LOG_PARAM_HEADER((spc3_log_params_header_t *)
2N/A (&(dp->lpst_prh)));
2N/A
2N/A dl_fprintf(stream,
2N/A "SELF-TEST RESULT: %d SELF-TEST CODE : %d\n"
2N/A "SELF-TEST NUMBER: %d TIMESTAMP : %d\n"
2N/A "ADDR : 0x%llx\n"
2N/A "SENSE KEY: %d ASC: %d ASCQ: %d VS: %d\n\n",
2N/A dp->lpst_str, dp->lpst_stc, dp->lpst_st_no,
2N/A SCSI_READ16(&(dp->lpst_timestamp)),
2N/A SCSI_READ64(&(dp->lpst_addr00)), dp->lpst_sense_key,
2N/A dp->lpst_asc, dp->lpst_ascq, dp->lpst_vs);
2N/A
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_back_scan(char *log_back_scan_data, int len, FILE *stream)
2N/A{
2N/A int i, j;
2N/A int code, param_len;
2N/A char *status = "RESERVED";
2N/A const struct scan_status {
2N/A int scode;
2N/A char *s_str;
2N/A } extended_scan_status[] = {
2N/A { DL_LPBS_SC_NONE, "NO ACTIVE BACK SCAN" },
2N/A { DL_LPBS_SC_MEDIUM, "BACK MEDIUM SCAN ACTIVE" },
2N/A { DL_LPBS_SC_PRESCAN, "BACK PRE-SCAN ACTIVE" },
2N/A { DL_LPBS_SC_FATAL,
2N/A "BACK SCAN HALTED DUE TO FATAL ERR" },
2N/A { DL_LPBS_SC_VENDOR_ERR,
2N/A "BACK SCAN HALTED DUE TO VENDOR SPECIFIC PATTERN OF ERRS" },
2N/A { DL_LPBS_SC_NO_PLIST,
2N/A "BACK SCAN HALTED DUE TO MEDIUM FORMATTED WITHOUT P-LIST" },
2N/A { DL_LPBS_SC_VENDOR_CAUSE,
2N/A "BACK SCAN HALTED DUE TOH VENDOR CAUSE" },
2N/A { DL_LPBS_SC_HIGH_TEMP,
2N/A "BACK SCAN HALTED DUE TO TOO HIGH TEMPERATURE" },
2N/A { DL_LPBS_SC_INACTIVE,
2N/A "BACK MEDIUM SCAN ENABLED, BUT NO ONE INACTIVE" },
2N/A { 0xfff, NULL }
2N/A };
2N/A spc3_log_params_header_t *hp;
2N/A dl_log_params_back_scan_status_t *dp0;
2N/A dl_log_params_medium_scan_t *dp;
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A dp0 = (dl_log_params_back_scan_status_t *)(&log_back_scan_data[i]);
2N/A
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_log_params_header) > len) {
2N/A dl_fprintf(stream, "Log back scan page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A hp = (spc3_log_params_header_t *)(&log_back_scan_data[i]);
2N/A param_len = sizeof (struct spc3_log_params_header) +
2N/A hp->lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log back scan page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A code = SCSI_READ16(&(hp->lph_param_code));
2N/A if (code > DL_LOG_PC_BACK_SCAN_STATUS) {
2N/A dp = (dl_log_params_medium_scan_t *)
2N/A (&log_back_scan_data[i]);
2N/A if (code > DL_LOG_PC_BACK_SCAN_END) {
2N/A i += param_len;
2N/A continue;
2N/A }
2N/A }
2N/A
2N/A dl_fprintf(stream,
2N/A "PARAM CODE : %04xh (%s)\n",
2N/A code, (code == DL_LOG_PC_BACK_SCAN_STATUS ?
2N/A "STATUS PARAMETER" : "MEDIUM SCAN PARAMETER"));
2N/A PRINT_LOG_PARAM_HEADER(hp);
2N/A
2N/A for (j = 0; extended_scan_status[j].s_str != NULL; j++) {
2N/A if (extended_scan_status[j].scode ==
2N/A dp0->lpbss_status) {
2N/A status = extended_scan_status[j].s_str;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (code == DL_LOG_PC_BACK_SCAN_STATUS)
2N/A dl_fprintf(stream,
2N/A "ACCUMULATED POWER ON MINUTES: %d\n"
2N/A "BACKGROUND SCAN STATUS : %s\n"
2N/A "NUMBER OF BACKGROUND SCANS PERFORMED : "
2N/A "%d\n"
2N/A "BACKGROUND SCAN PROGRESS : "
2N/A "%.2f%%\n"
2N/A "NUMBER OF BACKGROUND MEDIUM SCANS PERFORMED : "
2N/A "%d\n\n",
2N/A SCSI_READ32(&(dp0->lpbss_apom)), status,
2N/A SCSI_READ16(&(dp0->lpbss_number_of_bsp)),
2N/A DL_BACK_SCAN_PROGRESS_PERCENT(
2N/A SCSI_READ16(&(dp0->lpbss_progress))),
2N/A SCSI_READ16(&(dp0->lpbss_number_of_bmsp)));
2N/A else if ((code > DL_LOG_PC_BACK_SCAN_STATUS) &&
2N/A (code <= DL_LOG_PC_BACK_SCAN_END)) {
2N/A dl_fprintf(stream,
2N/A "ACCUMULATED POWER ON MINUTES: %d\n"
2N/A "SENSE KEY : 0x%x "
2N/A "REASSIGN STATUS : %d\n"
2N/A "ASC: 0x%02x ASCQ: 0x%02x",
2N/A SCSI_READ32(&(dp->lpms_apom)), dp->lpms_sense_key,
2N/A dp->lpms_reassign_status, dp->lpms_asc,
2N/A dp->lpms_ascq);
2N/A dl_fprintf(stream, " LBA: 0x");
2N/A print_hex_value((char *)dp->lpms_lba,
2N/A sizeof (dp->lpms_lba), stream);
2N/A dl_fprintf(stream, "\n\n");
2N/A } else
2N/A dl_fprintf(stream, "UNDEFINED PARAM CODE\n\n");
2N/A
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_protocol(char *log_protocol_data, int len, FILE *stream)
2N/A{
2N/A int i, j, k;
2N/A int phy_number;
2N/A int phy_event_number;
2N/A int type = 0;
2N/A int desc_len2;
2N/A int desc_len3;
2N/A char *attached_reason = "RESERVED";
2N/A char *reason = "RESERVED";
2N/A char *dev_type = "RESERVED";
2N/A char *link_rate = "RESERVED";
2N/A char *type_string = "RESERVED";
2N/A dl_log_params_protocol_port_header_t *dp1;
2N/A dl_log_params_protocol_spld_header_t *dp2;
2N/A dl_log_params_protocol_ped_t *dp3;
2N/A const struct reason {
2N/A int reason_code;
2N/A char *reason_str;
2N/A } extended_reason[] = {
2N/A { DL_LOG_P_REASON_UNKOWN, "UNKNOWN REASON" },
2N/A { DL_LOG_P_REASON_POWERON, "POWER ON" },
2N/A { DL_LOG_P_REASON_HARDRESET, "HARD RESET" },
2N/A { DL_LOG_P_REASON_SMP, "SMP PHY CONTROL FUNCTION" },
2N/A { DL_LOG_P_REASON_LOSS_OF_DWORD,
2N/A "LOSS OF DWORD SYNCHRONIZATION" },
2N/A { DL_LOG_P_REASON_MUX, "MUX RECEIVED" },
2N/A { DL_LOG_P_REASON_IT, "I_T NEXUS LOSS TIMER EXPIRED" },
2N/A { DL_LOG_P_REASON_TIMEOUT, "BREAK TIMEOUT TIMER EXPIRED" },
2N/A { DL_LOG_P_REASON_STOP, "PHY TEST FUNCTION STOPPED" },
2N/A { DL_LOG_P_REASON_EXP, "EXPANDER DEVICE REDUCED FUNCTIONALITY" },
2N/A { 0xff, NULL }
2N/A };
2N/A const struct dev_type {
2N/A int type_code;
2N/A char *type_str;
2N/A } extended_dev_type[] = {
2N/A { DL_LOG_PD_TYPE_NONE, "NO DEVICE ATTACHED" },
2N/A { DL_LOG_PD_TYPE_END_DEV, "SAS DEVICE OR SATA DEVICE" },
2N/A { DL_LOG_PD_TYPE_EXPANDER, "EXPANDER DEVICE" },
2N/A { DL_LOG_PD_TYPE_EXPANDER_COMPLIANT,
2N/A "EXPANDER DEVICE COMPLIANT WITH A PREVIOUS VERSION"},
2N/A { 0xf, NULL }
2N/A };
2N/A const struct link_rate {
2N/A int rate_code;
2N/A char *rate_str;
2N/A } extended_link_rate[] = {
2N/A { DL_LOG_PL_RATE_UNKOWN,
2N/A "PHY ENABLED, UNKNOWN PHYISCAL LINK RATE" },
2N/A { DL_LOG_PL_RATE_DISABLED, "PHY DISABLED" },
2N/A { DL_LOG_PL_RATE_PHY_RESET,
2N/A "PHY ENABLED, A PHY RESET PROBLEM OCCURRED" },
2N/A { DL_LOG_PL_RATE_SPINUP_HOLD, "PHY ENABLED, SPINUP_HOLD STATE" },
2N/A { DL_LOG_PL_RATE_PORT_SELECTOR, "PHY ENABLED, PORT_SELECTOR" },
2N/A { DL_LOG_PL_RATE_RESET, "PHY ENABLED, RESET IN PROGRESS" },
2N/A { DL_LOG_PL_RATE_UNSUPPORTED_PHY,
2N/A "PHY ENABLED, UNSUPPORTED PHY ATTACHED" },
2N/A { DL_LOG_PL_RESERVED, "RESERVED" },
2N/A { DL_LOG_PL_RATE_G1, "PHY ENABLED, 1.5 GBPS" },
2N/A { DL_LOG_PL_RATE_G2, "PHY ENABLED, 3 GBPS" },
2N/A { DL_LOG_PL_RATE_G3, "PHY ENABLED, 6 GBPS" },
2N/A { 0xff, NULL }
2N/A };
2N/A const struct phy_event_string {
2N/A int phy_type;
2N/A char *phy_string;
2N/A } event_strs[] = {
2N/A { DL_LOG_PPEN_NO_EVENT, "NO EVENT" },
2N/A { DL_LOG_PPEN_INVALID_DWORD_CNT, "INVALID WORD COUNT" },
2N/A { DL_LOG_PPEN_DISPARITY_ERR_CNT,
2N/A "RUNNING DISPARITY ERROR COUNT" },
2N/A { DL_LOG_PPEN_LOSS_OF_DWORD,
2N/A "LOSS OF DWORD SYNCHRONIZATION COUNT" },
2N/A { DL_LOG_PPEN_PHY_RESET_CNT, "PHY RESET PROBLEM COUNT" },
2N/A { DL_LOG_PPEN_BUF_OVERFLOW_CNT,
2N/A "ELASTICITY BUFFER OVERFLOW COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_ERR_CNT, "RECEIVED ERROR COUNT" },
2N/A { DL_LOG_PPEN_ADDR_ERR_CNT,
2N/A "RECEIVED ADDRESS FRAME ERROR COUNT" },
2N/A { DL_LOG_PPEN_TRANSMITTED_ABANDON_CNT,
2N/A "TRANSMITTED ABANDON-CLASS OPEN_REJECT COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_ABANDON_CNT,
2N/A "RECEIVED ABANDON-CLASS OPEN_REJECT COUNT" },
2N/A { DL_LOG_PPEN_TRANSMITTED_RETRY_CNT,
2N/A "TRANSMITTED RETRY-CLASS OPEN_REJECT COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_RETRY_CNT,
2N/A "RECEIVED RETRY-CLASS OPEN_REJECT COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_AIP_PART_CNT,
2N/A "RECEIVED AIP(WAITING ON PARTIAL) COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_AIP_CONN_CNT,
2N/A "RECEIVED AIP(WAITING ON CONNECTION) COUNT" },
2N/A { DL_LOG_PPEN_TRANSMITTED_BREAK_CNT, "TRANSMITTED BREAK COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_BREAK_CNT, "RECEIVED BREAK COUNT" },
2N/A { DL_LOG_PPEN_BREAK_TIMEOUT_CNT, "BREAK TIMEOUT COUNT" },
2N/A { DL_LOG_PPEN_CONN_CNT, "CONNECTION COUNT" },
2N/A { DL_LOG_PPEN_PEAK_BLOCKED_CNT,
2N/A "PEAK TRANSMITTED PATHWAY BLOCKED COUNT" },
2N/A { DL_LOG_PPEN_PEAK_WAIT_TIME,
2N/A "PEAK TRANSMITTED ARBITRATION WAIT TIME" },
2N/A { DL_LOG_PPEN_PEAK_ARBI_TIME, "PEAK ARBITRATION TIME" },
2N/A { DL_LOG_PPEN_PEAK_CONN_TIME, "PEAK CONNECTION TIME" },
2N/A { DL_LOG_PPEN_TRANSMITTED_SSP_CNT,
2N/A "TRANSMITTED SSP FRAME COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_SSP_CNT, "RECEIVED SSP FRAME COUNT" },
2N/A { DL_LOG_PPEN_TRANSMITTED_SSP_ERR_CNT,
2N/A "TRANSMITTED SSP FRAME ERROR COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_SSP_ERR_CNT,
2N/A "RECEIVED SSP FRAME ERROR COUNT" },
2N/A { DL_LOG_PPEN_TRANSMITTED_CB_CNT,
2N/A "TRANSMITTED CREDIT_BLOCKED COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_CB_CNT, "RECEIVED CREDIT_BLOCKED COUNT" },
2N/A { DL_LOG_PPEN_TRANSMITTED_SATA_CNT,
2N/A "TRANSMITTED SATA FRAME COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_SATA_CNT, "RECEIVED SATA FRAME COUNT" },
2N/A { DL_LOG_PPEN_SATA_BUF_CNT,
2N/A "SATA FLOW CONTROL BUFFER OVERFLOW COUNT" },
2N/A { DL_LOG_PPEN_TRANSMITTED_SMP_CNT,
2N/A "TRANSMITTED SMP FRAME COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_SMP_CNT, "RECEIVED SMP FRAME COUNT" },
2N/A { DL_LOG_PPEN_RECEIVED_SMP_ERR_CNT,
2N/A "RECEIVED SMP FRAME ERROR COUNT" },
2N/A { 0xffff, NULL }
2N/A };
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A while (i < len) {
2N/A if (i + sizeof (struct dl_log_params_protocol_port_header) >
2N/A len) {
2N/A dl_fprintf(stream, "Log protocol page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A dp1 = (dl_log_params_protocol_port_header_t *)
2N/A (&log_protocol_data[i]);
2N/A if (dp1->lppph_id != DL_LOG_PP_ID_SAS) {
2N/A print_buf(log_protocol_data, len, stream);
2N/A break;
2N/A }
2N/A
2N/A dl_fprintf(stream, "PARAM CODE : %04xh\n",
2N/A SCSI_READ16(&(dp1->lppph_prh.lph_param_code)));
2N/A PRINT_LOG_PARAM_HEADER((spc3_log_params_header_t *)
2N/A (&(dp1->lppph_prh)));
2N/A phy_number = dp1->lppph_number_of_phys;
2N/A dl_fprintf(stream,
2N/A "PROTOCOL IDENTIFIER : SAS SERIAL SCSI PROTOCOL\n"
2N/A "GENERATION CODE : %d NUMBER OF PHYS : %d\n",
2N/A dp1->lppph_generation_code, phy_number);
2N/A
2N/A i += sizeof (struct dl_log_params_protocol_port_header);
2N/A
2N/A while (phy_number > 0) {
2N/A dp2 = (dl_log_params_protocol_spld_header_t *)
2N/A (&log_protocol_data[i]);
2N/A desc_len2 =
2N/A sizeof (dl_log_params_protocol_spld_header_t);
2N/A if (dp2->lppsh_spld_len == 0)
2N/A desc_len2 = DL_DEFAULT_SAS_PHY_LOG_DESC_LEN;
2N/A
2N/A if (i + desc_len2 > len) {
2N/A dl_fprintf(stream, "Log protocol page, "
2N/A "SAS phy log descriptor invalid\n");
2N/A i += desc_len2;
2N/A break;
2N/A }
2N/A
2N/A for (k = 0; extended_reason[k].reason_str != NULL;
2N/A k++) {
2N/A if (extended_reason[k].reason_code ==
2N/A dp2->lppsh_attached_reason) {
2N/A attached_reason =
2N/A extended_reason[k].reason_str;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A for (k = 0; extended_dev_type[k].type_str != NULL;
2N/A k++) {
2N/A if (extended_dev_type[k].type_code ==
2N/A dp2->lppsh_attached_dev_type) {
2N/A dev_type =
2N/A extended_dev_type[k].type_str;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A for (k = 0; extended_link_rate[k].rate_str != NULL;
2N/A k++) {
2N/A if (extended_link_rate[k].rate_code ==
2N/A dp2->lppsh_link_rate) {
2N/A link_rate =
2N/A extended_link_rate[k].rate_str;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A for (k = 0; extended_reason[k].reason_str != NULL;
2N/A k++) {
2N/A if (extended_reason[k].reason_code ==
2N/A dp2->lppsh_reason) {
2N/A reason =
2N/A extended_reason[k].reason_str;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A dl_fprintf(stream,
2N/A "PHY IDENTIFIER : %d\n"
2N/A "SAS_PHY_LOG_DESCRIPTOR_LENGTH : "
2N/A "%d\n"
2N/A "ATTACHED REASON : %s\n"
2N/A "ATTACHED DEVICE : %s\n"
2N/A "NEGOTIATED LOGICAL LINK RATE: %s\n"
2N/A "REASON : %s\n"
2N/A "ATTACHED INITIATOR PORT\n"
2N/A "SMP: %d STP: %d SSP: %d\n"
2N/A "ATTACHED TARGET PORT\n"
2N/A "SMP: %d STP: %d SSP: %d\n",
2N/A dp2->lppsh_phy_id, dp2->lppsh_spld_len,
2N/A attached_reason, dev_type, link_rate, reason,
2N/A dp2->lppsh_attached_smpi, dp2->lppsh_attached_stpi,
2N/A dp2->lppsh_attached_sspi, dp2->lppsh_attached_smpt,
2N/A dp2->lppsh_attached_stpt, dp2->lppsh_attached_sspt);
2N/A dl_fprintf(stream,
2N/A "SAS ADDR : 0x");
2N/A print_hex_value((char *)dp2->lppsh_sas_addr,
2N/A sizeof (dp2->lppsh_sas_addr), stream);
2N/A dl_fprintf(stream, "\n");
2N/A dl_fprintf(stream,
2N/A "ATTACHED SAS ADDR : 0x");
2N/A print_hex_value((char *)dp2->lppsh_attached_sas_addr,
2N/A sizeof (dp2->lppsh_attached_sas_addr), stream);
2N/A dl_fprintf(stream, "\n");
2N/A
2N/A dl_fprintf(stream,
2N/A "ATTACHED PHY ID : %d\n"
2N/A "INVALID DWORD COUNT : %d\n"
2N/A "RUNNING DISPARITY ERR COUNT : %d\n"
2N/A "LOSS OF DWORD SYNC : %d\n"
2N/A "PHY RESET PROBLEM : %d\n",
2N/A dp2->lppsh_attached_phy_id,
2N/A SCSI_READ32(&(dp2->lppsh_invalid_dword_cnt)),
2N/A SCSI_READ32(&(dp2->lppsh_disparity_err_cnt)),
2N/A SCSI_READ32(&(dp2->lppsh_loss_of_dword_sync)),
2N/A SCSI_READ32(&(dp2->lppsh_phy_reset_problem)));
2N/A
2N/A if (dp2->lppsh_spld_len == 0) {
2N/A phy_number--;
2N/A i += desc_len2;
2N/A dl_fprintf(stream, "\n");
2N/A continue;
2N/A }
2N/A
2N/A phy_event_number = dp2->lppsh_number_of_phy_event;
2N/A dl_fprintf(stream,
2N/A "PHY EVENT DESCRIPTOR LEN : %d\n"
2N/A "# OF PHY EVENT DESCRIPTORS : %d\n",
2N/A dp2->lppsh_phy_event_descriptor_len,
2N/A phy_event_number);
2N/A
2N/A i += desc_len2;
2N/A
2N/A while (phy_event_number > 0) {
2N/A desc_len3 =
2N/A sizeof (dl_log_params_protocol_ped_t);
2N/A if (i + desc_len3 > len) {
2N/A dl_fprintf(stream, "Log protocol page"
2N/A ", phy event descriptor invalid\n");
2N/A i += desc_len3;
2N/A break;
2N/A }
2N/A dp3 = (dl_log_params_protocol_ped_t *)
2N/A (&log_protocol_data[i]);
2N/A
2N/A for (j = 0; event_strs[j].phy_type !=
2N/A 0xffff && event_strs[j].phy_string !=
2N/A NULL; j++) {
2N/A if (event_strs[j].phy_type ==
2N/A dp3->lppp_phy_event_source) {
2N/A type = event_strs[j].phy_type;
2N/A type_string =
2N/A event_strs[j].phy_string;
2N/A break;
2N/A }
2N/A }
2N/A dl_fprintf(stream,
2N/A "PHY EVENT SOURCE: %s\n"
2N/A "PHY EVEMT VALUE : %d\n",
2N/A type_string,
2N/A SCSI_READ32(&(dp3->lppp_phy_event)));
2N/A if (type == DL_LOG_PPEN_PEAK_BLOCKED_CNT ||
2N/A type == DL_LOG_PPEN_PEAK_WAIT_TIME ||
2N/A type == DL_LOG_PPEN_PEAK_ARBI_TIME ||
2N/A type == DL_LOG_PPEN_PEAK_CONN_TIME)
2N/A dl_fprintf(stream,
2N/A "PEAK VAL DETECTOR THRESHOLD: %d"
2N/A "\n", SCSI_READ32(
2N/A &(dp3->lppp_peak_val)));
2N/A
2N/A phy_event_number--;
2N/A i += desc_len3;
2N/A }
2N/A phy_number--;
2N/A dl_fprintf(stream, "\n");
2N/A }
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_ie(char *log_ie_data, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A int param_len;
2N/A spc3_log_params_ie_header_t *dp;
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A while (i < len) {
2N/A if (i + sizeof (struct spc3_log_params_header) > len) {
2N/A dl_fprintf(stream, "Log ie page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A dp = (spc3_log_params_ie_header_t *)(&log_ie_data[i]);
2N/A param_len = sizeof (struct spc3_log_params_header) +
2N/A dp->lpih_prh.lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log ie page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A dl_fprintf(stream, "PARAM CODE : %04xh\n",
2N/A SCSI_READ16(&(dp->lpih_prh.lph_param_code)));
2N/A PRINT_LOG_PARAM_HEADER((spc3_log_params_header_t *)
2N/A (&(dp->lpih_prh)));
2N/A
2N/A if (dp->lpih_prh.lph_prlen >= sizeof (dp->lpih_asc) +
2N/A sizeof (dp->lpih_ascq))
2N/A dl_fprintf(stream,
2N/A "INFORMATIONAl EXCEPTION ASC : %d\n"
2N/A "INFORMATIONAL EXCEPTION ASCQ: %d\n",
2N/A dp->lpih_asc, dp->lpih_ascq);
2N/A
2N/A if (dp->lpih_prh.lph_prlen >=
2N/A sizeof (struct spc3_log_params_ie_header) -
2N/A sizeof (struct spc3_log_params_header))
2N/A dl_fprintf(stream,
2N/A "MOST RECENT TEMPERATURE : %d C\n",
2N/A dp->lpih_t);
2N/A
2N/A dl_fprintf(stream, "\n");
2N/A
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_cache(char *log_cache_data, int len, FILE *stream)
2N/A{
2N/A int i, j;
2N/A int code;
2N/A int hdr_len, param_len;
2N/A char *cache_str;
2N/A const struct cache_string {
2N/A int cache_code;
2N/A char *cache_str;
2N/A } extended_cache_string[] = {
2N/A { DL_LOG_PC_SEAGATE_CACHE_BLKSENT,
2N/A "BLOCKS SENT TO INITIATOR " },
2N/A { DL_LOG_PC_SEAGATE_CACHE_BLKRECV,
2N/A "BLOCKS RECEIVED FROM INITIATOR " },
2N/A { DL_LOG_PC_SEAGATE_CACHE_BLKREAD,
2N/A "BLOCKS READ FROM CACHE AND SENT TO INITIATOR " },
2N/A { DL_LOG_PC_SEAGATE_CACHE_SMALLSZ,
2N/A "COMMAND # OF R/W WHOSE SIZE <= SEGMENT SIZE " },
2N/A { DL_LOG_PC_SEAGATE_CACHE_BIGSZ,
2N/A "COMMAND # OF R/W WHOSE SIZE >= SEGMENT SIZE " },
2N/A { 0xfffff, NULL }
2N/A };
2N/A spc3_log_params_header_t *hp;
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A
2N/A while (i < len) {
2N/A hdr_len = sizeof (struct spc3_log_params_header);
2N/A if (i + hdr_len > len) {
2N/A dl_fprintf(stream, "Log cache page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A hp = (spc3_log_params_header_t *)(&log_cache_data[i]);
2N/A param_len = hdr_len + hp->lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log cache page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A code = SCSI_READ16(&(hp->lph_param_code));
2N/A
2N/A dl_fprintf(stream, "PARAM CODE : %04xh\n", code);
2N/A PRINT_LOG_PARAM_HEADER(hp);
2N/A
2N/A for (j = 0; extended_cache_string[j].cache_str != NULL; j++) {
2N/A if (extended_cache_string[j].cache_code == code) {
2N/A cache_str = extended_cache_string[j].cache_str;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A if (code >= DL_LOG_PC_SEAGATE_CACHE_BLKSENT &&
2N/A code <= DL_LOG_PC_SEAGATE_CACHE_BIGSZ) {
2N/A if (hp->lph_prlen > sizeof (uint64_t))
2N/A dl_fprintf(stream, "%s: %llu\n\n",
2N/A cache_str,
2N/A SCSI_READ64(&(log_cache_data[i + hdr_len +
2N/A hp->lph_prlen - sizeof (uint64_t)])));
2N/A else {
2N/A dl_fprintf(stream, "%s: ", cache_str);
2N/A print_decimal_value(
2N/A &log_cache_data[i + hdr_len], hp->lph_prlen,
2N/A stream);
2N/A dl_fprintf(stream, "\n\n");
2N/A }
2N/A } else
2N/A dl_fprintf(stream,
2N/A "UNKNOWN SEAGATE PARAMETER CODE: %04xh\n", code);
2N/A
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_log_factory(char *log_factory_data, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A int code;
2N/A int hdr_len, param_len;
2N/A spc3_log_params_header_t *hp;
2N/A
2N/A i = sizeof (struct spc3_log_page_header);
2N/A
2N/A while (i < len) {
2N/A hdr_len = sizeof (struct spc3_log_params_header);
2N/A if (i + hdr_len > len) {
2N/A dl_fprintf(stream, "Log factory page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A hp = (spc3_log_params_header_t *)(&log_factory_data[i]);
2N/A param_len = hdr_len + hp->lph_prlen;
2N/A if (i + param_len > len) {
2N/A dl_fprintf(stream, "Log factory page invalid\n");
2N/A break;
2N/A }
2N/A
2N/A code = SCSI_READ16(&(hp->lph_param_code));
2N/A dl_fprintf(stream, "PARAM CODE : %04xh\n", code);
2N/A PRINT_LOG_PARAM_HEADER(hp);
2N/A if (code == DL_LOG_PC_SEAGATE_FACTORY_HOURS)
2N/A dl_fprintf(stream, "NUMBER OF HOURS POWERED UP"
2N/A " : %.2f\n\n",
2N/A ((double)SCSI_READ32(
2N/A &(log_factory_data[i + hdr_len]))) / 60.0);
2N/A else if (code == DL_LOG_PC_SEAGATE_FACTORY_MINUTES)
2N/A dl_fprintf(stream, "MINUTES # UNTIL NEXT INTERNAL "
2N/A "SMART TEST : %d\n\n",
2N/A SCSI_READ32(&(log_factory_data[i + hdr_len])));
2N/A else
2N/A dl_fprintf(stream,
2N/A "UNKOWN SEAGATE/HITACHI PARAM CODE\n\n");
2N/A i += param_len;
2N/A }
2N/A}
2N/A
2N/Astatic int
2N/Aactual_mode_len(char *mode_data, int len)
2N/A{
2N/A spc3_mode_param_header10_t *hp;
2N/A
2N/A hp = (spc3_mode_param_header10_t *)mode_data;
2N/A
2N/A return (MIN((SCSI_READ16(&(hp->mph_mode_data_length)) +
2N/A sizeof (hp->mph_mode_data_length)), len));
2N/A}
2N/A
2N/Astatic int
2N/Astore_mode_supported_pages(char *mode_pages, int len, char *pages_buf)
2N/A{
2N/A int i, k;
2N/A uint8_t page, next_page;
2N/A spc3_mode_param_header10_t *hp;
2N/A spc3_mode_page_0_t *pp;
2N/A spc3_mode_subpage_t *sp;
2N/A
2N/A hp = (spc3_mode_param_header10_t *)mode_pages;
2N/A i = sizeof (struct spc3_mode_param_header10) +
2N/A SCSI_READ16(&(hp->mph_block_descriptor_length));
2N/A
2N/A for (k = 0; i < len; ) {
2N/A pp = (spc3_mode_page_0_t *)(&mode_pages[i]);
2N/A page = pp->mp0_page_code & SPC3_MODE_PC_ALL;
2N/A pages_buf[k] = page;
2N/A
2N/A i += sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters) + pp->mp0_page_length;
2N/A next_page = (uint8_t)mode_pages[i] & SPC3_MODE_PC_ALL;
2N/A for (; i < len && next_page == page; ) {
2N/A sp = (spc3_mode_subpage_t *)(&mode_pages[i]);
2N/A k += 2;
2N/A pages_buf[k] = next_page;
2N/A pages_buf[k + 1] = sp->ms_subpage_code;
2N/A i += sizeof (struct spc3_mode_subpage) -
2N/A sizeof (sp->ms_mode_parameters) +
2N/A SCSI_READ16(&(sp->ms_page_length));
2N/A next_page = (uint8_t)mode_pages[i] & SPC3_MODE_PC_ALL;
2N/A }
2N/A k += 2;
2N/A }
2N/A
2N/A return (k);
2N/A}
2N/A
2N/Astatic boolean_t
2N/Ais_mode_page_supported(int pc, int spc, char *mode_pages, int len)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i += 2)
2N/A if ((pc == (uint8_t)mode_pages[i]) &&
2N/A (spc == (uint8_t)mode_pages[i + 1]))
2N/A return (B_TRUE);
2N/A
2N/A return (B_FALSE);
2N/A}
2N/A
2N/Astatic void
2N/Aprint_mode_supported_pages(char *mode_pages, int len, FILE *stream)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i += 2) {
2N/A dl_fprintf(stream, "%02xh", mode_pages[i]);
2N/A
2N/A if ((uint8_t)mode_pages[i + 1] != 0)
2N/A dl_fprintf(stream, "(%02xh) ",
2N/A (uint8_t)mode_pages[i + 1]);
2N/A else
2N/A dl_fprintf(stream, " ");
2N/A }
2N/A
2N/A dl_fprintf(stream, "\n\n");
2N/A}
2N/A
2N/Astatic void
2N/Aparse_mode_all(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A char *mode_pages, int len, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i += 2) {
2N/A if ((mode_pages[i] != SPC3_MODE_PC_ALL) &&
2N/A ((uint8_t)mode_pages[i + 1] != SPC3_MODE_SPC_ALL))
2N/A disklog_send_mode_sense(
2N/A hp, tp, mode_pages[i], mode_pages[i + 1], stream,
2N/A flags);
2N/A }
2N/A
2N/A dl_fprintf(stream, "\n");
2N/A}
2N/A
2N/Astatic void
2N/Aparse_subpage_failure(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A int pc, FILE *stream, dl_flags_t flags)
2N/A{
2N/A disklog_send_mode_sense(hp, tp, pc, DL_MODE_SPC_NONE, stream, flags);
2N/A}
2N/A
2N/Astatic void
2N/Aparse_mode_basic_pages(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A char *mode_pages, int len, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int i;
2N/A const struct page_codes {
2N/A int page_code;
2N/A int subpage_code;
2N/A } extended_page_codes [] = {
2N/A { SPC3_MODE_PC_CTL, SPC3_MODE_SPC_CTL },
2N/A { SPC3_MODE_PC_CTL_EXT, SPC3_MODE_SPC_CTL_EXT },
2N/A { SPC3_MODE_PC_DIS_RE, SPC3_MODE_SPC_DIS_RE },
2N/A { SPC3_MODE_PC_IE_CTL, SPC3_MODE_SPC_IE_CTL },
2N/A { SPC3_MODE_PC_PC, SPC3_MODE_SPC_PC },
2N/A { 0xffff, 0xffff }
2N/A };
2N/A
2N/A for (i = 0; extended_page_codes[i].page_code != 0xffff &&
2N/A extended_page_codes[i].subpage_code != 0xffff; i++)
2N/A if ((is_mode_page_supported(extended_page_codes[i].page_code,
2N/A extended_page_codes[i].subpage_code, mode_pages, len))
2N/A == B_TRUE)
2N/A disklog_send_mode_sense(hp, tp,
2N/A extended_page_codes[i].page_code,
2N/A extended_page_codes[i].subpage_code, stream, flags);
2N/A}
2N/A
2N/Astatic void
2N/Aparse_mode_all_subpages(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A int pc, int spc, char *mode_pages, int len, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int i;
2N/A
2N/A for (i = 0; i < len; i += 2)
2N/A if (pc == mode_pages[i])
2N/A disklog_send_mode_sense(hp, tp, pc,
2N/A (uint8_t)mode_pages[i + 1], stream, flags);
2N/A
2N/A if (pc == SPC3_MODE_PC_ALL) {
2N/A print_page_name_string(SPC3_CMD_MODE_SENSE10, pc, spc, stream);
2N/A print_mode_supported_pages(mode_pages, len, stream);
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Aprint_mode_ctl(char *mode_ctl_data, int len, FILE *stream)
2N/A{
2N/A int hdr_len;
2N/A spc3_mode_page_params_control_t *dp;
2N/A spc3_mode_param_header10_t *hp;
2N/A spc3_mode_page_0_t *pp;
2N/A
2N/A hp = (spc3_mode_param_header10_t *)mode_ctl_data;
2N/A hdr_len = sizeof (struct spc3_mode_param_header10) +
2N/A SCSI_READ16(&(hp->mph_block_descriptor_length));
2N/A pp = (spc3_mode_page_0_t *)(&(mode_ctl_data[hdr_len]));
2N/A if (len < (hdr_len + sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters) + pp->mp0_page_length)) {
2N/A dl_fprintf(stream, "Control Mode Page data incomplete\n\n");
2N/A return;
2N/A }
2N/A
2N/A dp = (spc3_mode_page_params_control_t *)(&(mode_ctl_data[
2N/A hdr_len + sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters)]));
2N/A
2N/A dl_fprintf(stream,
2N/A "RLEC: %d GLTSD: %d D_SENSE : %d TMF_ONLY: %d TST: %d\n"
2N/A "QERR: %d QUEUE ALGORITHM MODIFIER: %d SWP : %d\n"
2N/A "UA_INTLCK_CTRL: %d RAC: %d VS: %d AUTOLOAD MODE : %d\n"
2N/A "TAS : %d ATO: %d BUSY TIMEOUT PERIOD: %d\n"
2N/A "EXTENDED SELF-TEST COMPLETION TIME : %d\n\n",
2N/A dp->mpc_rlec, dp->mpc_gltsd, dp->mpc_d_sense, dp->mpc_tmf_only,
2N/A dp->mpc_tst, dp->mpc_q_err, dp->mpc_queue_alg_mod, dp->mpc_swp,
2N/A dp->mpc_ua_intlck_ctrl, dp->mpc_rac, dp->mpc_vs_4_7,
2N/A dp->mpc_autoload_mode, dp->mpc_tas, dp->mpc_ato,
2N/A SCSI_READ16(&dp->mpc_busy_timeout_period),
2N/A SCSI_READ16(&dp->mpc_ext_selftest_completion_time));
2N/A}
2N/A
2N/Astatic void
2N/Aprint_mode_ctl_ext(char *mode_ctl_ext_data, int len, FILE *stream)
2N/A{
2N/A int hdr_len;
2N/A spc3_mode_params_control_ext_t *dp;
2N/A spc3_mode_param_header10_t *hp;
2N/A spc3_mode_subpage_t *sp;
2N/A
2N/A hp = (spc3_mode_param_header10_t *)mode_ctl_ext_data;
2N/A hdr_len = sizeof (struct spc3_mode_param_header10) +
2N/A SCSI_READ16(&(hp->mph_block_descriptor_length));
2N/A sp = (spc3_mode_subpage_t *)(&(mode_ctl_ext_data[hdr_len]));
2N/A if (len < (hdr_len + sizeof (struct spc3_mode_subpage) -
2N/A sizeof (sp->ms_mode_parameters) +
2N/A SCSI_READ16(&(sp->ms_page_length)))) {
2N/A dl_fprintf(stream,
2N/A "Control Extension Mode Page data incomplete\n\n");
2N/A return;
2N/A }
2N/A
2N/A dp = (spc3_mode_params_control_ext_t *)(&(mode_ctl_ext_data[
2N/A hdr_len + sizeof (struct spc3_mode_subpage) -
2N/A sizeof (sp->ms_mode_parameters)]));
2N/A
2N/A dl_fprintf(stream,
2N/A "IALUAE: %d SCSIP: %d TCMOS: %d "
2N/A "Initial command priority: %d\n\n",
2N/A dp->mpce_ialuae, dp->mpce_scsip, dp->mpce_tcmos,
2N/A dp->mpce_initial_priority);
2N/A}
2N/A
2N/Astatic void
2N/Aprint_mode_dcrc(char *mode_dcrc_data, int len, FILE *stream)
2N/A{
2N/A int hdr_len;
2N/A spc3_mode_params_dc_rc_t *dp;
2N/A spc3_mode_param_header10_t *hp;
2N/A spc3_mode_page_0_t *pp;
2N/A
2N/A hp = (spc3_mode_param_header10_t *)mode_dcrc_data;
2N/A hdr_len = sizeof (struct spc3_mode_param_header10) +
2N/A SCSI_READ16(&(hp->mph_block_descriptor_length));
2N/A pp = (spc3_mode_page_0_t *)(&(mode_dcrc_data[hdr_len]));
2N/A if (len < (hdr_len + sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters) + pp->mp0_page_length)) {
2N/A dl_fprintf(stream,
2N/A "Disconnect-Reconnect Mode Page data incomplete\n");
2N/A return;
2N/A }
2N/A
2N/A dp = (spc3_mode_params_dc_rc_t *)(&(mode_dcrc_data[
2N/A hdr_len + sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters)]));
2N/A
2N/A dl_fprintf(stream,
2N/A "BUFFER FULL RATIO : %d\n"
2N/A "BUFFER EMPTY RATIO : %d\n"
2N/A "BUS INACTIVITY LIMIT : %d\n"
2N/A "DISCONNECT TIME LIMIT: %d\n"
2N/A "CONNECT TIME LIMIT : %d\n"
2N/A "MAX BURST SIZE : %d\n"
2N/A "DTDC: %d DIMM: %d FAIR ARBITRATION : %d\n"
2N/A "EMDP: %d FIRST BURST SIZE : %d\n\n",
2N/A dp->mpdr_buffer_full_ratio, dp->mpdr_buffer_empty_ratio,
2N/A SCSI_READ16(&dp->mpdr_bus_inactivity_limit),
2N/A SCSI_READ16(&dp->mpdr_disconnect_time_limit),
2N/A SCSI_READ16(&dp->mpdr_connect_time_limit),
2N/A SCSI_READ16(&dp->mpdr_max_burst_size),
2N/A dp->mpdr_dtdc, dp->mpdr_di_mm, dp->mpdr_fair_arbitration,
2N/A dp->mpdr_emdp, SCSI_READ16(&dp->mpdr_first_burst_size));
2N/A}
2N/A
2N/Astatic void
2N/Aprint_mode_iec(char *mode_iec_data, int len, FILE *stream)
2N/A{
2N/A int hdr_len;
2N/A spc3_mode_params_iec_t *dp;
2N/A spc3_mode_param_header10_t *hp;
2N/A spc3_mode_page_0_t *pp;
2N/A
2N/A hp = (spc3_mode_param_header10_t *)mode_iec_data;
2N/A hdr_len = sizeof (struct spc3_mode_param_header10) +
2N/A SCSI_READ16(&(hp->mph_block_descriptor_length));
2N/A pp = (spc3_mode_page_0_t *)(&(mode_iec_data[hdr_len]));
2N/A if (len < (hdr_len + sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters) + pp->mp0_page_length)) {
2N/A dl_fprintf(stream,
2N/A "Information Exception Control Mode Page "
2N/A "data incomplete\n\n");
2N/A return;
2N/A }
2N/A
2N/A dp = (spc3_mode_params_iec_t *)(&(mode_iec_data[
2N/A hdr_len + sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters)]));
2N/A
2N/A dl_fprintf(stream,
2N/A "LOGERR: %d TEST: %d DEXCPT: %d EWASC: %d EBF : %d\n"
2N/A "PERF : %d MRIE: %d INTERVAL TIMER : %u\n"
2N/A "EPORT COUNT : %u\n\n",
2N/A dp->mpi_log_err, dp->mpi_test, dp->mpi_d_excpt, dp->mpi_e_wasc,
2N/A dp->mpi_ebf, dp->mpi_perf, dp->mpi_mrie,
2N/A SCSI_READ32(&(dp->mpi_interval_timer)),
2N/A SCSI_READ32(&(dp->mpi_report_count)));
2N/A}
2N/A
2N/Astatic void
2N/Aprint_mode_pc(char *mode_pc_data, int len, FILE *stream)
2N/A{
2N/A int hdr_len;
2N/A spc3_mode_params_pc_t *dp;
2N/A spc3_mode_param_header10_t *hp;
2N/A spc3_mode_page_0_t *pp;
2N/A
2N/A hp = (spc3_mode_param_header10_t *)mode_pc_data;
2N/A hdr_len = sizeof (struct spc3_mode_param_header10) +
2N/A SCSI_READ16(&(hp->mph_block_descriptor_length));
2N/A pp = (spc3_mode_page_0_t *)(&(mode_pc_data[hdr_len]));
2N/A if (len < (hdr_len + sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters) + pp->mp0_page_length)) {
2N/A dl_fprintf(stream,
2N/A "Power Condition Mode Page data incomplete\n\n");
2N/A return;
2N/A }
2N/A
2N/A dp = (spc3_mode_params_pc_t *)(&(mode_pc_data[
2N/A hdr_len + sizeof (struct spc3_mode_page_0) -
2N/A sizeof (pp->mp0_mode_parameters)]));
2N/A
2N/A dl_fprintf(stream,
2N/A "STANDBY: %d IDLE : %d\nIDLE CONDITION TIMER : %u\n"
2N/A "STANDBY CONDITION TIMER: %u\n\n",
2N/A dp->mpp_standby, dp->mpp_idle,
2N/A SCSI_READ32(&(dp->mpp_idle_condition_timer)),
2N/A SCSI_READ32(&(dp->mpp_standby_condition_timer)));
2N/A}
2N/A
2N/Astatic void
2N/Aprint_sense(libscsi_action_t *ap, FILE *stream)
2N/A{
2N/A uint64_t key, asc, ascq;
2N/A const char *code, *keystr;
2N/A
2N/A if (libscsi_action_parse_sense(ap, &key, &asc, &ascq, NULL) != 0) {
2N/A dl_fprintf(stream, "command failed with status 0x%x "
2N/A "(no sense data available)",
2N/A libscsi_action_get_status(ap));
2N/A return;
2N/A }
2N/A
2N/A code = libscsi_sense_code_name(asc, ascq);
2N/A keystr = libscsi_sense_key_name(key);
2N/A
2N/A dl_fprintf(stream,
2N/A "SCSI status = 0x%x\nsense key = 0x%llx (%s)\n"
2N/A "sense code = 0x%llx/0x%llx (%s)\n\n",
2N/A libscsi_action_get_status(ap), key,
2N/A (keystr == NULL ? "unknown" : keystr), asc, ascq,
2N/A (code == NULL ? "unknown" : code));
2N/A}
2N/A
2N/Aint
2N/Adisklog_open_device(libscsi_hdl_t **hpp, libscsi_target_t **tpp,
2N/A const char *dev, boolean_t quiet_flag, FILE *stream)
2N/A{
2N/A libscsi_errno_t err;
2N/A
2N/A if ((*hpp = libscsi_init(LIBSCSI_VERSION, &err)) == NULL) {
2N/A dl_fprintf(stream, "libscsi initialization failed: %s\n",
2N/A libscsi_strerror(err));
2N/A return (DL_FAILURE);
2N/A }
2N/A if ((*tpp = libscsi_open(*hpp, "uscsi", dev)) == NULL) {
2N/A libscsi_fini(*hpp);
2N/A if (quiet_flag == B_FALSE)
2N/A dl_fprintf(stream, "failed to open %s: %s\n",
2N/A dev, libscsi_errmsg(*hpp));
2N/A return (DL_FAILURE);
2N/A }
2N/A
2N/A return (DL_SUCCESS);
2N/A}
2N/A
2N/Avoid
2N/Adisklog_close_device(libscsi_hdl_t *hp, libscsi_target_t *tp)
2N/A{
2N/A libscsi_close(hp, tp);
2N/A libscsi_fini(hp);
2N/A}
2N/A
2N/A/*
2N/A * Send an inquiry page request. Provides the ability to request a particular
2N/A * inquiry page for the scsi target specified by the libscsi_target_t parameter.
2N/A * This includes the ability to request all inquiry pages supported by the
2N/A * target. Once retrieved call the appropriate parse function and print the
2N/A * data to the stream.
2N/A */
2N/Avoid
2N/Adisklog_send_inquiry(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A boolean_t evpd, int pc, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int status;
2N/A int vpdpage_len;
2N/A char data[DL_INQ_DATALEN];
2N/A char vpdpage[DL_PAGELEN];
2N/A libscsi_action_t *ap;
2N/A spc3_inquiry_cdb_t *cp;
2N/A struct inquiry_parser {
2N/A spc3_inquiry_page_code_t pc;
2N/A void (*func)(char *, int, FILE *);
2N/A } inquiry_parsers[] = {
2N/A { SPC3_INQUIRY_PC_UNIT_SERIAL_NUMBER, print_inq_serialno },
2N/A { SPC3_INQUIRY_PC_DEV_ID, print_inq_page83 },
2N/A { SPC3_INQUIRY_PC_EXT_DATA, print_inq_ext },
2N/A { SPC3_INQUIRY_PC_MODE_PAGE_POLICY, print_inq_mode_policy },
2N/A { 0, NULL }
2N/A };
2N/A struct inquiry_parser *ip;
2N/A
2N/A ap = libscsi_action_alloc(hp, SPC3_CMD_INQUIRY,
2N/A LIBSCSI_AF_READ | LIBSCSI_AF_RQSENSE, data, DL_INQ_DATALEN);
2N/A if (ap == NULL) {
2N/A dl_fprintf(stream, "failed to allocate action: %s\n",
2N/A libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A cp = (spc3_inquiry_cdb_t *)libscsi_action_get_cdb(ap);
2N/A
2N/A cp->ic_evpd = evpd;
2N/A cp->ic_page_code = pc;
2N/A SCSI_WRITE16(&cp->ic_allocation_length, DL_INQ_DATALEN);
2N/A
2N/A if (libscsi_exec(ap, tp) != 0) {
2N/A libscsi_action_free(ap);
2N/A dl_fprintf(stream, "exec failed: %s\n", libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A status = libscsi_action_get_status(ap);
2N/A
2N/A if (status == SAM4_STATUS_GOOD) {
2N/A size_t len = 0;
2N/A
2N/A if (libscsi_action_get_buffer(ap, NULL, NULL, &len) != 0) {
2N/A libscsi_action_free(ap);
2N/A dl_fprintf(stream, "failed to obtain buffer: %s\n",
2N/A libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A if (!(evpd == B_TRUE && pc == SPC3_INQUIRY_PC_ALL &&
2N/A (flags.aflag == 1 || flags.bflag == 1 || flags.Aflag == 1)))
2N/A print_page_name_string(SPC3_CMD_INQUIRY,
2N/A (evpd == B_TRUE ? 1 : 0), pc, stream);
2N/A
2N/A if (evpd == B_FALSE) {
2N/A if (pc == 0)
2N/A print_inq_std(data, stream);
2N/A } else {
2N/A if (pc == SPC3_INQUIRY_PC_ALL) {
2N/A (void) memset(vpdpage, 0, DL_PAGELEN);
2N/A vpdpage_len = actual_inq_len(evpd, data, len) -
2N/A sizeof (struct spc3_inquiry_vpd_header);
2N/A (void) memcpy(vpdpage, &data[
2N/A sizeof (struct spc3_inquiry_vpd_header)],
2N/A vpdpage_len);
2N/A if (flags.aflag == 1 || flags.Aflag == 1)
2N/A parse_inq_all(hp, tp,
2N/A vpdpage, vpdpage_len, stream,
2N/A flags);
2N/A if (flags.eflag == 1)
2N/A print_inq_supported_pages(
2N/A vpdpage, vpdpage_len, stream);
2N/A if (flags.bflag == 1)
2N/A parse_inq_basic_pages(hp, tp,
2N/A vpdpage, vpdpage_len, stream,
2N/A flags);
2N/A } else {
2N/A for (ip = &inquiry_parsers[0]; ; ip++) {
2N/A if (ip->pc == pc && ip->func != NULL) {
2N/A ip->func(data, actual_inq_len(
2N/A evpd, data, len), stream);
2N/A break;
2N/A }
2N/A if (ip->func == NULL) {
2N/A print_buf(data, actual_inq_len(
2N/A evpd, data, len), stream);
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A }
2N/A } else {
2N/A print_page_name_string(SPC3_CMD_INQUIRY,
2N/A (evpd == B_TRUE ? 1 : 0), pc, stream);
2N/A print_sense(ap, stream);
2N/A }
2N/A libscsi_action_free(ap);
2N/A}
2N/A
2N/A/*
2N/A * Format and send a request to obtain the log pages from the the scsi target
2N/A * specified by the libscsi_target_t structure. These pages contain read/write
2N/A * error counters, verify error counters and etc. Once the data is retrieved
2N/A * call parse and print functions to write this data to the stream.
2N/A */
2N/Avoid
2N/Adisklog_send_log_sense(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A int pc, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int status;
2N/A int logpage_len;
2N/A char data[DL_DATALEN];
2N/A char logpage[DL_PAGELEN];
2N/A libscsi_action_t *ap;
2N/A spc3_log_sense_cdb_t *cp;
2N/A struct log_parser {
2N/A spc3_log_page_code_t pc;
2N/A void (*func)(char *, int, FILE *);
2N/A } log_parsers[] = {
2N/A { SPC3_LOG_PC_WRITE_ERR, print_log_error_counter },
2N/A { SPC3_LOG_PC_READ_ERR, print_log_error_counter },
2N/A { SPC3_LOG_PC_READ_REV_ERR, print_log_error_counter },
2N/A { SPC3_LOG_PC_VERIFY_ERR, print_log_error_counter },
2N/A { SPC3_LOG_PC_NON_MEDIUM, print_log_non_medium },
2N/A { SPC3_LOG_PC_TEMPERATURE, print_log_temperature },
2N/A { SPC3_LOG_PC_START_STOP, print_log_start_stop },
2N/A { SPC3_LOG_PC_SELF_TEST, print_log_self_test },
2N/A { DL_LOG_PC_BACK_SCAN, print_log_back_scan },
2N/A { SPC3_LOG_PC_PROTOCOL, print_log_protocol },
2N/A { SPC3_LOG_PC_IE, print_log_ie },
2N/A { DL_LOG_PC_SEAGATE_CACHE, print_log_cache },
2N/A { DL_LOG_PC_SEAGATE_FACTORY, print_log_factory },
2N/A { 0, NULL }
2N/A };
2N/A struct log_parser *lp;
2N/A
2N/A ap = libscsi_action_alloc(hp, SPC3_CMD_LOG_SENSE,
2N/A LIBSCSI_AF_READ | LIBSCSI_AF_RQSENSE, data, DL_DATALEN);
2N/A if (ap == NULL) {
2N/A dl_fprintf(stream, "failed to allocate action: %s\n",
2N/A libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A cp = (spc3_log_sense_cdb_t *)libscsi_action_get_cdb(ap);
2N/A cp->lsc_page_code = pc;
2N/A cp->lsc_pc = SPC3_LOG_PC_CUR_CUMULATIVE;
2N/A SCSI_WRITE16(&cp->lsc_allocation_length, DL_DATALEN);
2N/A
2N/A if (libscsi_exec(ap, tp) != 0) {
2N/A libscsi_action_free(ap);
2N/A dl_fprintf(stream, "exec failed: %s\n", libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A status = libscsi_action_get_status(ap);
2N/A
2N/A if (status == SAM4_STATUS_GOOD) {
2N/A size_t len = 0;
2N/A
2N/A if (libscsi_action_get_buffer(ap, NULL, NULL, &len) != 0) {
2N/A libscsi_action_free(ap);
2N/A dl_fprintf(stream, "failed to obtain buffer: %s\n",
2N/A libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A if (!((pc == SPC3_LOG_PC_ALL) &&
2N/A (flags.aflag == 1 || flags.bflag == 1 || flags.Aflag == 1)))
2N/A print_page_name_string(
2N/A SPC3_CMD_LOG_SENSE, pc, 0, stream);
2N/A
2N/A if (pc == SPC3_LOG_PC_ALL) {
2N/A (void) memset(logpage, 0, DL_PAGELEN);
2N/A logpage_len = actual_log_len(data, len) -
2N/A sizeof (struct spc3_log_page_header);
2N/A (void) memcpy(logpage, &data[
2N/A sizeof (struct spc3_log_page_header)], logpage_len);
2N/A if (flags.aflag == 1 || flags.Aflag == 1)
2N/A parse_log_all(
2N/A hp, tp, logpage, logpage_len, stream,
2N/A flags);
2N/A if (flags.eflag == 1 || flags.lflag == 1)
2N/A print_log_supported_pages(
2N/A logpage, logpage_len, stream);
2N/A if (flags.bflag == 1)
2N/A parse_log_basic_pages(
2N/A hp, tp, logpage, logpage_len, stream,
2N/A flags);
2N/A } else {
2N/A for (lp = &log_parsers[0]; ; lp++) {
2N/A if (lp->pc == pc && lp->func != NULL) {
2N/A lp->func(data, actual_log_len(
2N/A data, len), stream);
2N/A break;
2N/A }
2N/A if (lp->func == NULL) {
2N/A print_buf(data, actual_log_len(
2N/A data, len), stream);
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A } else {
2N/A print_page_name_string(SPC3_CMD_LOG_SENSE, pc, 0, stream);
2N/A print_sense(ap, stream);
2N/A }
2N/A libscsi_action_free(ap);
2N/A}
2N/A
2N/A/*
2N/A * Format and send a request to obtain the mode pages from the the scsi target
2N/A * specified by the libscsi_target_t structure. These pages will contain data
2N/A * like the informational Exception settings and data. Once the data is
2N/A * retrieved call parse and print functions to write this data to the stream.
2N/A */
2N/Avoid
2N/Adisklog_send_mode_sense(libscsi_hdl_t *hp, libscsi_target_t *tp,
2N/A int pc, int spc, FILE *stream, dl_flags_t flags)
2N/A{
2N/A int status;
2N/A int modepage_len;
2N/A int store_pc = SPC3_MODE_PC_ALL;
2N/A char data[DL_DATALEN];
2N/A char modepage[DL_PAGELEN];
2N/A libscsi_action_t *ap;
2N/A spc3_mode_sense10_cdb_t *cp;
2N/A struct mode_parser {
2N/A spc3_mode_page_code_t pc;
2N/A spc3_mode_sub_page_code_t spc;
2N/A void (*func)(char *, int, FILE *);
2N/A } mode_parsers[] = {
2N/A { SPC3_MODE_PC_CTL, SPC3_MODE_SPC_CTL, print_mode_ctl },
2N/A { SPC3_MODE_PC_CTL_EXT, SPC3_MODE_SPC_CTL_EXT, print_mode_ctl_ext },
2N/A { SPC3_MODE_PC_DIS_RE, SPC3_MODE_SPC_DIS_RE, print_mode_dcrc },
2N/A { SPC3_MODE_PC_IE_CTL, SPC3_MODE_SPC_IE_CTL, print_mode_iec },
2N/A { SPC3_MODE_PC_PC, SPC3_MODE_SPC_PC, print_mode_pc},
2N/A { 0, NULL }
2N/A };
2N/A struct mode_parser *mp;
2N/A
2N/A ap = libscsi_action_alloc(hp, SPC3_CMD_MODE_SENSE10,
2N/A LIBSCSI_AF_READ | LIBSCSI_AF_RQSENSE, data, DL_DATALEN);
2N/A if (ap == NULL) {
2N/A dl_fprintf(stream, "failed to allocate action: %s\n",
2N/A libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A if (spc == DL_MODE_SPC_SPECIAL) {
2N/A store_pc = pc;
2N/A pc = SPC3_MODE_PC_ALL;
2N/A spc = SPC3_MODE_SPC_ALL;
2N/A }
2N/A
2N/A cp = (spc3_mode_sense10_cdb_t *)libscsi_action_get_cdb(ap);
2N/A
2N/A /* Send mode sense command to get supported pages and subpages */
2N/A cp->msc_page_code = pc;
2N/A cp->msc_subpage_code = spc;
2N/A SCSI_WRITE16(&cp->msc_allocation_length, DL_DATALEN);
2N/A
2N/A if (libscsi_exec(ap, tp) != 0) {
2N/A libscsi_action_free(ap);
2N/A dl_fprintf(stream, "exec failed: %s\n", libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A status = libscsi_action_get_status(ap);
2N/A
2N/A if (status == SAM4_STATUS_GOOD) {
2N/A size_t len = 0;
2N/A
2N/A if (libscsi_action_get_buffer(ap, NULL, NULL, &len) != 0) {
2N/A libscsi_action_free(ap);
2N/A dl_fprintf(stream, "failed to obtain buffer: %s\n",
2N/A libscsi_errmsg(hp));
2N/A return;
2N/A }
2N/A
2N/A if (!((flags.aflag == 1 || flags.bflag == 1 ||
2N/A flags.Aflag == 1 ||
2N/A (flags.mflag == 1 && flags.m1_flag == 0)) &&
2N/A (pc == SPC3_MODE_PC_ALL)))
2N/A print_page_name_string(
2N/A SPC3_CMD_MODE_SENSE10, pc, spc, stream);
2N/A
2N/A if (pc == SPC3_MODE_PC_ALL) {
2N/A (void) memset(modepage, 0, DL_PAGELEN);
2N/A modepage_len = store_mode_supported_pages(
2N/A data, actual_mode_len(data, len), modepage);
2N/A if (flags.aflag == 1 || flags.Aflag == 1)
2N/A parse_mode_all(
2N/A hp, tp, modepage, modepage_len, stream,
2N/A flags);
2N/A if (flags.mflag == 1 && flags.m1_flag == 0)
2N/A parse_mode_all_subpages(hp, tp, store_pc,
2N/A spc, modepage, modepage_len, stream, flags);
2N/A if (flags.eflag == 1 || flags.mflag == 1 &&
2N/A flags.m1_flag == 1)
2N/A print_mode_supported_pages(
2N/A modepage, modepage_len, stream);
2N/A if (flags.bflag == 1)
2N/A parse_mode_basic_pages(
2N/A hp, tp, modepage, modepage_len, stream,
2N/A flags);
2N/A } else {
2N/A for (mp = &mode_parsers[0]; ; mp++) {
2N/A if (mp->pc == pc && mp->spc == spc &&
2N/A mp->func != NULL) {
2N/A mp->func(data, actual_mode_len(
2N/A data, len), stream);
2N/A break;
2N/A }
2N/A if (mp->func == NULL) {
2N/A print_buf(data, actual_mode_len(
2N/A data, len), stream);
2N/A break;
2N/A }
2N/A }
2N/A }
2N/A } else if (spc == SPC3_MODE_SPC_ALL) {
2N/A if (flags.mflag == 1 && flags.m1_flag == 0)
2N/A parse_subpage_failure(hp, tp, store_pc, stream, flags);
2N/A else
2N/A parse_subpage_failure(hp, tp, pc, stream, flags);
2N/A } else {
2N/A print_page_name_string(SPC3_CMD_MODE_SENSE10, pc, spc, stream);
2N/A print_sense(ap, stream);
2N/A }
2N/A libscsi_action_free(ap);
2N/A}
2N/A
2N/A/*
2N/A * Create a directory if it doesn't exist.
2N/A * Parameters:
2N/A * path: The directory path to create.
2N/A * mode: The mode used when creating the directory.
2N/A * If the indicated path does not exist, attempt to create it, if is does exist
2N/A * verify whether it is a directory or not.
2N/A */
2N/Astatic int
2N/Ado_mkdir(const char *path, mode_t mode)
2N/A{
2N/A struct stat st;
2N/A int status = 0;
2N/A
2N/A if (stat(path, &st) != 0) {
2N/A /* Directory does not exist */
2N/A if (mkdir(path, mode) != 0)
2N/A status = -1;
2N/A } else if (!S_ISDIR(st.st_mode)) {
2N/A errno = ENOTDIR;
2N/A status = -1;
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A/*
2N/A * Walk the indcated path, checking whether each directory exists by calling
2N/A * the do_mkdir function.
2N/A */
2N/Astatic int
2N/Acheck_path(char *path, mode_t mode)
2N/A{
2N/A char *pp;
2N/A char *sp;
2N/A int status = 0;
2N/A
2N/A pp = path;
2N/A while (status == 0 && (sp = strchr(pp, '/')) != 0) {
2N/A if (sp != pp) {
2N/A /* Neither root nor double slash in path */
2N/A *sp = '\0';
2N/A status = do_mkdir(path, mode);
2N/A *sp = '/';
2N/A }
2N/A pp = sp + 1;
2N/A }
2N/A
2N/A return (status);
2N/A}
2N/A
2N/A
2N/Astatic boolean_t
2N/Aget_diskname(const char *pathname, char *diskname)
2N/A{
2N/A char *pname;
2N/A
2N/A pname = strrchr(pathname, '/');
2N/A if (pname == NULL)
2N/A return (B_FALSE);
2N/A
2N/A (void) snprintf(diskname, MAXPATHLEN, "%s", &pname[1]);
2N/A
2N/A if ((pname = strchr(diskname, 'c')) == NULL ||
2N/A (pname = strchr(diskname, 't')) == NULL ||
2N/A (pname = strchr(diskname, 'd')) == NULL)
2N/A return (B_FALSE);
2N/A
2N/A if ((pname = strchr(diskname, 'p')) != NULL ||
2N/A (pname = strchr(diskname, 's')) != NULL)
2N/A *pname = '\0';
2N/A
2N/A return (B_TRUE);
2N/A}
2N/A
2N/Aint
2N/Adisklog_print_diskinfo(dl_logging_args_t *args)
2N/A{
2N/A int fd;
2N/A int retval;
2N/A char dev_wd[MAXPATHLEN];
2N/A char dev_s2[MAXPATHLEN];
2N/A char filename[MAXNAMELEN];
2N/A char diskname[MAXPATHLEN];
2N/A char *devidstr;
2N/A char *minor;
2N/A char *path;
2N/A FILE *stream;
2N/A libscsi_hdl_t *hp;
2N/A libscsi_target_t *tp;
2N/A ddi_devid_t devid = NULL;
2N/A devid_nmlist_t *list = NULL;
2N/A
2N/A if (args == NULL) {
2N/A dprintf("disklog_print_diskinfo was passed a NULL parameter\n");
2N/A return (LDL_INVALID_PARAM);
2N/A }
2N/A
2N/A /* Retrieve the devid from the args. */
2N/A devidstr = args->devid;
2N/A
2N/A if (devidstr == NULL)
2N/A return (LDL_INVALID_PARAM);
2N/A
2N/A if (devid_str_decode(devidstr, &devid, &minor) == -1) {
2N/A dprintf("decode %s fail\n", devidstr);
2N/A return (LDL_DEVID_DECODE_FAIL);
2N/A }
2N/A
2N/A retval = devid_deviceid_to_nmlist(DL_DEV, devid, minor, &list);
2N/A if (retval == -1 || (path = strdup(list[0].devname)) == NULL) {
2N/A devid_str_free(minor);
2N/A if (devid != NULL)
2N/A devid_free(devid);
2N/A if (list != NULL)
2N/A devid_free_nmlist(list);
2N/A dprintf("failed to get dev path\n");
2N/A return (LDL_DEVPATH_DECODE_FAIL);
2N/A }
2N/A
2N/A devid_str_free(minor);
2N/A devid_free(devid);
2N/A devid_free_nmlist(list);
2N/A
2N/A (void) memset(diskname, 0, MAXPATHLEN);
2N/A if (!get_diskname(path, diskname)) {
2N/A dprintf("invalid disk name from path %s\n", path);
2N/A if (path != NULL)
2N/A free(path);
2N/A return (LDL_INVALID_DISK_NAME);
2N/A }
2N/A
2N/A free(path);
2N/A
2N/A (void) memset(filename, 0, MAXNAMELEN);
2N/A if (args->uuid != NULL)
2N/A (void) snprintf(filename, sizeof (filename), "%s/%s.%s%s",
2N/A args->dir, diskname, args->uuid, DL_FILENAME_SUF);
2N/A else
2N/A (void) snprintf(filename, sizeof (filename), "%s/%s%s",
2N/A args->dir, diskname, DL_FILENAME_SUF);
2N/A
2N/A /* Verify/create the output directory. */
2N/A if (check_path(filename,
2N/A S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
2N/A dprintf("Directory %s does not exist and could not be "
2N/A "created. %s\n", args->dir, strerror(errno));
2N/A return (LDL_DIR_CREATE_ERROR);
2N/A }
2N/A
2N/A fd = open(filename, O_CREAT | O_EXCL | O_WRONLY,
2N/A S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
2N/A if (fd < 0) {
2N/A dprintf("Creation of %s failed (%d)\n", filename, fd);
2N/A return (LDL_FILE_ERROR);
2N/A }
2N/A stream = fdopen(fd, DL_FILEMODE);
2N/A if (stream == NULL) {
2N/A dprintf("Could not open a stream for %s : %s\n",
2N/A filename, strerror(errno));
2N/A (void) close(fd);
2N/A return (LDL_FILE_ERROR);
2N/A }
2N/A
2N/A (void) memset(dev_wd, 0, MAXPATHLEN);
2N/A (void) memset(dev_s2, 0, MAXPATHLEN);
2N/A
2N/A (void) snprintf(dev_wd, sizeof (dev_wd), "%s%s%s", DL_DEVICES,
2N/A args->devpath, DL_DISKWD);
2N/A (void) snprintf(dev_s2, sizeof (dev_s2), "%s%s%s", DL_DEVICES,
2N/A args->devpath, DL_DISKS2);
2N/A
2N/A if (disklog_open_device(
2N/A &hp, &tp, dev_s2, B_TRUE, stream) != DL_SUCCESS) {
2N/A if (disklog_open_device(&hp, &tp,
2N/A dev_wd, B_FALSE, stream) != DL_SUCCESS) {
2N/A (void) fclose(stream);
2N/A (void) close(fd);
2N/A return (LDL_DISK_OPEN_ERROR);
2N/A }
2N/A }
2N/A
2N/A disklog_send_inquiry(
2N/A hp, tp, B_TRUE, SPC3_INQUIRY_PC_ALL, stream, args->flags);
2N/A disklog_send_log_sense(hp, tp, SPC3_LOG_PC_ALL, stream,
2N/A args->flags);
2N/A disklog_send_mode_sense(hp, tp,
2N/A SPC3_MODE_PC_ALL, SPC3_MODE_SPC_ALL, stream, args->flags);
2N/A disklog_close_device(hp, tp);
2N/A
2N/A
2N/A (void) fclose(stream);
2N/A (void) close(fd);
2N/A
2N/A dprintf("%s created\n", filename);
2N/A
2N/A return (LDL_SUCCESS);
2N/A}