smp_all.c revision 298431
118334Speter/*- 290075Sobrien * Copyright (c) 2010 Spectra Logic Corporation 390075Sobrien * All rights reserved. 418334Speter * 590075Sobrien * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 790075Sobrien * are met: 890075Sobrien * 1. Redistributions of source code must retain the above copyright 990075Sobrien * notice, this list of conditions, and the following disclaimer, 1090075Sobrien * without modification. 1118334Speter * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1290075Sobrien * substantially similar to the "NO WARRANTY" disclaimer below 1390075Sobrien * ("Disclaimer") and any redistribution must be conditioned upon 1490075Sobrien * including a substantially similar Disclaimer requirement for further 1590075Sobrien * binary redistribution. 1618334Speter * 1718334Speter * NO WARRANTY 1890075Sobrien * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1990075Sobrien * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2090075Sobrien * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 2118334Speter * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2218334Speter * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2318334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2450397Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2590075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2618334Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2790075Sobrien * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28117395Skan * POSSIBILITY OF SUCH DAMAGES. 29117395Skan * 3090075Sobrien * $Id: //depot/users/kenm/FreeBSD-test/sys/cam/scsi/smp_all.c#4 $ 31117395Skan */ 32117395Skan 33117395Skan/* 3418334Speter * Serial Management Protocol helper functions. 3550397Sobrien */ 36117395Skan 3790075Sobrien#include <sys/cdefs.h> 3890075Sobrien__FBSDID("$FreeBSD: head/sys/cam/scsi/smp_all.c 298431 2016-04-21 19:40:10Z pfg $"); 3990075Sobrien 4090075Sobrien#include <sys/param.h> 41117395Skan#include <sys/types.h> 42117395Skan#ifdef _KERNEL 4350397Sobrien#include <sys/systm.h> 4418334Speter#include <sys/libkern.h> 4518334Speter#include <sys/kernel.h> 4618334Speter#else /* _KERNEL */ 4718334Speter#include <errno.h> 4818334Speter#include <stdio.h> 4918334Speter#include <stdlib.h> 5018334Speter#include <string.h> 5118334Speter#include <inttypes.h> 5218334Speter#endif /* _KERNEL */ 5318334Speter 5418334Speter#include <cam/cam.h> 5518334Speter#include <cam/cam_ccb.h> 5618334Speter#include <cam/cam_xpt.h> 5718334Speter#include <cam/scsi/smp_all.h> 5818334Speter#include <sys/sbuf.h> 5990075Sobrien 6090075Sobrien#ifndef _KERNEL 6190075Sobrien#include <camlib.h> 6218334Speter#endif 6390075Sobrien 6490075Sobrienstatic char *smp_yesno(int val); 6590075Sobrien 6690075Sobrienstatic char * 6718334Spetersmp_yesno(int val) 6890075Sobrien{ 6990075Sobrien char *str; 7018334Speter 7190075Sobrien if (val) 7290075Sobrien str = "Yes"; 7390075Sobrien else 7490075Sobrien str = "No"; 7596263Sobrien 7690075Sobrien return (str); 7790075Sobrien} 7890075Sobrien 7918334Speterstruct smp_error_table_entry { 8090075Sobrien uint8_t function_result; 8190075Sobrien const char *desc; 8290075Sobrien}; 8390075Sobrien 8490075Sobrien/* List current as of SPL Revision 7 */ 8590075Sobrienstatic struct smp_error_table_entry smp_error_table[] = { 8690075Sobrien {SMP_FR_ACCEPTED, "SMP Function Accepted"}, 8790075Sobrien {SMP_FR_UNKNOWN_FUNC, "Unknown SMP Function"}, 8890075Sobrien {SMP_FR_FUNCTION_FAILED, "SMP Function Failed"}, 8990075Sobrien {SMP_FR_INVALID_REQ_FRAME_LEN, "Invalid Request Frame Length"}, 9090075Sobrien {SMP_FR_INVALID_EXP_CHG_CNT, "Invalid Expander Change Count"}, 9190075Sobrien {SMP_FR_BUSY, "Busy"}, 9290075Sobrien {SMP_FR_INCOMPLETE_DESC_LIST, "Incomplete Descriptor List"}, 9390075Sobrien {SMP_FR_PHY_DOES_NOT_EXIST, "Phy Does Not Exist"}, 9490075Sobrien {SMP_FR_INDEX_DOES_NOT_EXIST, "Index Does Not Exist"}, 9518334Speter {SMP_FR_PHY_DOES_NOT_SUP_SATA, "Phy Does Not Support SATA"}, 9690075Sobrien {SMP_FR_UNKNOWN_PHY_OP, "Unknown Phy Operation"}, 9790075Sobrien {SMP_FR_UNKNOWN_PHY_TEST_FUNC, "Unknown Phy Test Function"}, 9890075Sobrien {SMP_FR_PHY_TEST_FUNC_INPROG, "Phy Test Function In Progress"}, 9990075Sobrien {SMP_FR_PHY_VACANT, "Phy Vacant"}, 10090075Sobrien {SMP_FR_UNKNOWN_PHY_EVENT_SRC, "Unknown Phy Event Source"}, 10190075Sobrien {SMP_FR_UNKNOWN_DESC_TYPE, "Unknown Descriptor Type"}, 10290075Sobrien {SMP_FR_UNKNOWN_PHY_FILTER, "Unknown Phy Filter"}, 10390075Sobrien {SMP_FR_AFFILIATION_VIOLATION, "Affiliation Violation"}, 10490075Sobrien {SMP_FR_SMP_ZONE_VIOLATION, "SMP Zone Violation"}, 10590075Sobrien {SMP_FR_NO_MGMT_ACCESS_RIGHTS, "No Management Access Rights"}, 10618334Speter {SMP_FR_UNKNOWN_ED_ZONING_VAL, "Unknown Enable Disable Zoning Value"}, 10718334Speter {SMP_FR_ZONE_LOCK_VIOLATION, "Zone Lock Violation"}, 10818334Speter {SMP_FR_NOT_ACTIVATED, "Not Activated"}, 10990075Sobrien {SMP_FR_ZG_OUT_OF_RANGE, "Zone Group Out of Range"}, 11090075Sobrien {SMP_FR_NO_PHYS_PRESENCE, "No Physical Presence"}, 11190075Sobrien {SMP_FR_SAVING_NOT_SUP, "Saving Not Supported"}, 11290075Sobrien {SMP_FR_SRC_ZONE_DNE, "Source Zone Group Does Not Exist"}, 11390075Sobrien {SMP_FR_DISABLED_PWD_NOT_SUP, "Disabled Password Not Supported"} 11490075Sobrien}; 11590075Sobrien 11690075Sobrienconst char * 11790075Sobriensmp_error_desc(int function_result) 11890075Sobrien{ 11990075Sobrien int i; 12090075Sobrien 12118334Speter for (i = 0; i < nitems(smp_error_table); i++){ 12218334Speter if (function_result == smp_error_table[i].function_result) 12318334Speter return (smp_error_table[i].desc); 12418334Speter } 12518334Speter return ("Reserved Function Result"); 12618334Speter} 12790075Sobrien 12890075Sobrien/* List current as of SPL Revision 7 */ 12918334Speterstruct smp_cmd_table_entry { 13018334Speter uint8_t cmd_num; 13118334Speter const char *desc; 13290075Sobrien} smp_cmd_table[] = { 13318334Speter {SMP_FUNC_REPORT_GENERAL, "REPORT GENERAL"}, 13490075Sobrien {SMP_FUNC_REPORT_MANUF_INFO, "REPORT MANUFACTURER INFORMATION"}, 13518334Speter {SMP_FUNC_REPORT_SC_STATUS, "REPORT SELF-CONFIGURATION STATUS"}, 13690075Sobrien {SMP_FUNC_REPORT_ZONE_PERM_TBL, "REPORT ZONE PERMISSION TABLE"}, 13790075Sobrien {SMP_FUNC_REPORT_BROADCAST, "REPORT BROADCAST"}, 13890075Sobrien {SMP_FUNC_DISCOVER, "DISCOVER"}, 13918334Speter {SMP_FUNC_REPORT_PHY_ERR_LOG, "REPORT PHY ERROR LOG"}, 14018334Speter {SMP_FUNC_REPORT_PHY_SATA, "REPORT PHY SATA"}, 14118334Speter {SMP_FUNC_REPORT_ROUTE_INFO, "REPORT ROUTE INFORMATION"}, 14218334Speter {SMP_FUNC_REPORT_PHY_EVENT, "REPORT PHY EVENT"}, 14390075Sobrien {SMP_FUNC_DISCOVER_LIST, "DISCOVER LIST"}, 14490075Sobrien {SMP_FUNC_REPORT_PHY_EVENT_LIST, "REPORT PHY EVENT LIST"}, 14518334Speter {SMP_FUNC_REPORT_EXP_RTL, "REPORT EXPANDER ROUTE TABLE LIST"}, 14618334Speter {SMP_FUNC_CONFIG_GENERAL, "CONFIGURE GENERAL"}, 14718334Speter {SMP_FUNC_ENABLE_DISABLE_ZONING, "ENABLE DISABLE ZONING"}, 14818334Speter {SMP_FUNC_ZONED_BROADCAST, "ZONED BROADCAST"}, 14918334Speter {SMP_FUNC_ZONE_LOCK, "ZONE LOCK"}, 15018334Speter {SMP_FUNC_ZONE_ACTIVATE, "ZONE ACTIVATE"}, 15196263Sobrien {SMP_FUNC_ZONE_UNLOCK, "ZONE UNLOCK"}, 15218334Speter {SMP_FUNC_CONFIG_ZM_PWD, "CONFIGURE ZONE MANAGER PASSWORD"}, 15318334Speter {SMP_FUNC_CONFIG_ZONE_PHY_INFO, "CONFIGURE ZONE PHY INFORMATION"}, 15418334Speter {SMP_FUNC_CONFIG_ZONE_PERM_TBL, "CONFIGURE ZONE PERMISSION TABLE"}, 15518334Speter {SMP_FUNC_CONFIG_ROUTE_INFO, "CONFIGURE ROUTE INFORMATION"}, 15618334Speter {SMP_FUNC_PHY_CONTROL, "PHY CONTROL"}, 15718334Speter {SMP_FUNC_PHY_TEST_FUNC, "PHY TEST FUNCTION"}, 15818334Speter {SMP_FUNC_CONFIG_PHY_EVENT, "CONFIGURE PHY EVENT"} 15918334Speter}; 16018334Speter 16190075Sobrienconst char * 16290075Sobriensmp_command_desc(uint8_t cmd_num) 16390075Sobrien{ 16490075Sobrien int i; 16590075Sobrien 16690075Sobrien for (i = 0; i < nitems(smp_cmd_table) && 16790075Sobrien smp_cmd_table[i].cmd_num <= cmd_num; i++) { 16890075Sobrien if (cmd_num == smp_cmd_table[i].cmd_num) 16990075Sobrien return (smp_cmd_table[i].desc); 17090075Sobrien } 17190075Sobrien 17290075Sobrien /* 17390075Sobrien * 0x40 to 0x7f and 0xc0 to 0xff are the vendor specific SMP 17490075Sobrien * command ranges. 17590075Sobrien */ 17618334Speter if (((cmd_num >= 0x40) && (cmd_num <= 0x7f)) 17718334Speter || (cmd_num >= 0xc0)) { 17818334Speter return ("Vendor Specific SMP Command"); 17990075Sobrien } else { 18090075Sobrien return ("Unknown SMP Command"); 18190075Sobrien } 18290075Sobrien} 183117395Skan 18490075Sobrien/* 18590075Sobrien * Decode a SMP request buffer into a string of hexadecimal numbers. 18690075Sobrien * 18790075Sobrien * smp_request: SMP request 18890075Sobrien * request_len: length of the SMP request buffer, may be reduced if the 18990075Sobrien * caller only wants part of the buffer printed 19050397Sobrien * sb: sbuf(9) buffer 19150397Sobrien * line_prefix: prefix for new lines, or an empty string ("") 19218334Speter * first_line_len: length left on first line 19318334Speter * line_len: total length of subsequent lines, 0 for no additional lines 19418334Speter * if there are no additional lines, first line will get ... 19518334Speter * at the end if there is additional data 19618334Speter */ 19790075Sobrienvoid 19890075Sobriensmp_command_decode(uint8_t *smp_request, int request_len, struct sbuf *sb, 19990075Sobrien char *line_prefix, int first_line_len, int line_len) 20090075Sobrien{ 20190075Sobrien int i, cur_len; 20290075Sobrien 20390075Sobrien for (i = 0, cur_len = first_line_len; i < request_len; i++) { 20490075Sobrien /* 20590075Sobrien * Each byte takes 3 characters. As soon as we go less 20690075Sobrien * than 6 (meaning we have at least 3 and at most 5 20790075Sobrien * characters left), check to see whether the subsequent 20890075Sobrien * line length (line_len) is long enough to bother with. 20918334Speter * If the user set it to 0, or some other length that isn't 21018334Speter * enough to hold at least the prefix and one byte, put ... 21118334Speter * on the first line to indicate that there is more data 21218334Speter * and bail out. 21318334Speter */ 21490075Sobrien if ((cur_len < 6) 21518334Speter && (line_len < (strlen(line_prefix) + 3))) { 21690075Sobrien sbuf_printf(sb, "..."); 21718334Speter return; 21890075Sobrien } 21918334Speter if (cur_len < 3) { 22018334Speter sbuf_printf(sb, "\n%s", line_prefix); 22118334Speter cur_len = line_len - strlen(line_prefix); 22218334Speter } 22390075Sobrien sbuf_printf(sb, "%02x ", smp_request[i]); 22490075Sobrien cur_len = cur_len - 3; 22518334Speter } 22618334Speter} 22718334Speter 22818334Spetervoid 22918334Spetersmp_command_sbuf(struct ccb_smpio *smpio, struct sbuf *sb, 23090075Sobrien char *line_prefix, int first_line_len, int line_len) 23190075Sobrien{ 23290075Sobrien sbuf_printf(sb, "%s. ", smp_command_desc(smpio->smp_request[1])); 23390075Sobrien 23490075Sobrien /* 23590075Sobrien * Acccount for the command description and the period and space 23690075Sobrien * after the command description. 23790075Sobrien */ 23890075Sobrien first_line_len -= strlen(smp_command_desc(smpio->smp_request[1])) + 2; 23990075Sobrien 24018334Speter smp_command_decode(smpio->smp_request, smpio->smp_request_len, sb, 24118334Speter line_prefix, first_line_len, line_len); 24218334Speter} 24318334Speter 24418334Speter/* 24518334Speter * Print SMP error output. For userland commands, we need the cam_device 24690075Sobrien * structure so we can get the path information from the CCB. 24790075Sobrien */ 24890075Sobrien#ifdef _KERNEL 24990075Sobrienvoid 25090075Sobriensmp_error_sbuf(struct ccb_smpio *smpio, struct sbuf *sb) 25190075Sobrien#else /* !_KERNEL*/ 25218334Spetervoid 25318334Spetersmp_error_sbuf(struct cam_device *device, struct ccb_smpio *smpio, 25490075Sobrien struct sbuf *sb) 25518334Speter#endif /* _KERNEL/!_KERNEL */ 25690075Sobrien{ 25790075Sobrien char path_str[64]; 25890075Sobrien 25990075Sobrien#ifdef _KERNEL 26090075Sobrien xpt_path_string(smpio->ccb_h.path, path_str, sizeof(path_str)); 26190075Sobrien#else 26290075Sobrien cam_path_string(device, path_str, sizeof(path_str)); 26390075Sobrien#endif 26450397Sobrien smp_command_sbuf(smpio, sb, path_str, 80 - strlen(path_str), 80); 26550397Sobrien sbuf_printf(sb, "\n"); 26618334Speter 26718334Speter sbuf_cat(sb, path_str); 26818334Speter sbuf_printf(sb, "SMP Error: %s (0x%x)\n", 26918334Speter smp_error_desc(smpio->smp_response[2]), 27018334Speter smpio->smp_response[2]); 27118334Speter} 272117395Skan 27318334Speter/* 274117395Skan * Decode the SMP REPORT GENERAL response. The format is current as of SPL 27590075Sobrien * Revision 7, but the parsing should be backward compatible for older 27690075Sobrien * versions of the spec. 27718334Speter */ 27818334Spetervoid 27990075Sobriensmp_report_general_sbuf(struct smp_report_general_response *response, 28018334Speter int response_len, struct sbuf *sb) 28190075Sobrien{ 28218334Speter sbuf_printf(sb, "Report General\n"); 28390075Sobrien sbuf_printf(sb, "Response Length: %d words (%d bytes)\n", 28490075Sobrien response->response_len, 28590075Sobrien response->response_len * SMP_WORD_LEN); 28618334Speter sbuf_printf(sb, "Expander Change Count: %d\n", 28718334Speter scsi_2btoul(response->expander_change_count)); 28818334Speter sbuf_printf(sb, "Expander Route Indexes: %d\n", 28918334Speter scsi_2btoul(response->expander_route_indexes)); 29018334Speter sbuf_printf(sb, "Long Response: %s\n", 29118334Speter smp_yesno(response->long_response & 29290075Sobrien SMP_RG_LONG_RESPONSE)); 29318334Speter sbuf_printf(sb, "Number of Phys: %d\n", response->num_phys); 29418334Speter sbuf_printf(sb, "Table to Table Supported: %s\n", 29518334Speter smp_yesno(response->config_bits0 & 29618334Speter SMP_RG_TABLE_TO_TABLE_SUP)); 29750397Sobrien sbuf_printf(sb, "Zone Configuring: %s\n", 29890075Sobrien smp_yesno(response->config_bits0 & 29950397Sobrien SMP_RG_ZONE_CONFIGURING)); 30050397Sobrien sbuf_printf(sb, "Self Configuring: %s\n", 30150397Sobrien smp_yesno(response->config_bits0 & 30250397Sobrien SMP_RG_SELF_CONFIGURING)); 30350397Sobrien sbuf_printf(sb, "STP Continue AWT: %s\n", 30450397Sobrien smp_yesno(response->config_bits0 & 30590075Sobrien SMP_RG_STP_CONTINUE_AWT)); 30650397Sobrien sbuf_printf(sb, "Open Reject Retry Supported: %s\n", 30750397Sobrien smp_yesno(response->config_bits0 & 30818334Speter SMP_RG_OPEN_REJECT_RETRY_SUP)); 30918334Speter sbuf_printf(sb, "Configures Others: %s\n", 31018334Speter smp_yesno(response->config_bits0 & 31118334Speter SMP_RG_CONFIGURES_OTHERS)); 31218334Speter sbuf_printf(sb, "Configuring: %s\n", 31318334Speter smp_yesno(response->config_bits0 & 31490075Sobrien SMP_RG_CONFIGURING)); 31518334Speter sbuf_printf(sb, "Externally Configurable Route Table: %s\n", 31618334Speter smp_yesno(response->config_bits0 & 31718334Speter SMP_RG_CONFIGURING)); 31818334Speter sbuf_printf(sb, "Enclosure Logical Identifier: 0x%016jx\n", 31918334Speter (uintmax_t)scsi_8btou64(response->encl_logical_id)); 32018334Speter 32118334Speter /* 32218334Speter * If the response->response_len is 0, then we don't have the 32318334Speter * extended information. Also, if the user didn't allocate enough 32418334Speter * space for the full request, don't try to parse it. 32518334Speter */ 32618334Speter if ((response->response_len == 0) 32718334Speter || (response_len < (sizeof(struct smp_report_general_response) - 32818334Speter sizeof(response->crc)))) 32918334Speter return; 33018334Speter 33118334Speter sbuf_printf(sb, "STP Bus Inactivity Time Limit: %d\n", 33218334Speter scsi_2btoul(response->stp_bus_inact_time_limit)); 33318334Speter sbuf_printf(sb, "STP Maximum Connect Time Limit: %d\n", 33418334Speter scsi_2btoul(response->stp_max_conn_time_limit)); 33518334Speter sbuf_printf(sb, "STP SMP I_T Nexus Loss Time: %d\n", 33618334Speter scsi_2btoul(response->stp_smp_it_nexus_loss_time)); 33718334Speter 33818334Speter sbuf_printf(sb, "Number of Zone Groups: %d\n", 33918334Speter (response->config_bits1 & SMP_RG_NUM_ZONE_GROUPS_MASK) >> 34018334Speter SMP_RG_NUM_ZONE_GROUPS_SHIFT); 34118334Speter sbuf_printf(sb, "Zone Locked: %s\n", 34218334Speter smp_yesno(response->config_bits1 & SMP_RG_ZONE_LOCKED)); 34318334Speter sbuf_printf(sb, "Physical Presence Supported: %s\n", 34418334Speter smp_yesno(response->config_bits1 & SMP_RG_PP_SUPPORTED)); 34518334Speter sbuf_printf(sb, "Physical Presence Asserted: %s\n", 34618334Speter smp_yesno(response->config_bits1 & SMP_RG_PP_ASSERTED)); 34718334Speter sbuf_printf(sb, "Zoning Supported: %s\n", 34818334Speter smp_yesno(response->config_bits1 & 34918334Speter SMP_RG_ZONING_SUPPORTED)); 35018334Speter sbuf_printf(sb, "Zoning Enabled: %s\n", 35118334Speter smp_yesno(response->config_bits1 & SMP_RG_ZONING_ENABLED)); 35290075Sobrien 35390075Sobrien sbuf_printf(sb, "Saving: %s\n", 35490075Sobrien smp_yesno(response->config_bits2 & SMP_RG_SAVING)); 35590075Sobrien sbuf_printf(sb, "Saving Zone Manager Password Supported: %s\n", 356117395Skan smp_yesno(response->config_bits2 & 35790075Sobrien SMP_RG_SAVING_ZM_PWD_SUP)); 35890075Sobrien sbuf_printf(sb, "Saving Zone Phy Information Supported: %s\n", 35990075Sobrien smp_yesno(response->config_bits2 & 36090075Sobrien SMP_RG_SAVING_PHY_INFO_SUP)); 36190075Sobrien sbuf_printf(sb, "Saving Zone Permission Table Supported: %s\n", 36290075Sobrien smp_yesno(response->config_bits2 & 36390075Sobrien SMP_RG_SAVING_ZPERM_TAB_SUP)); 36490075Sobrien sbuf_printf(sb, "Saving Zoning Enabled Supported: %s\n", 36590075Sobrien smp_yesno(response->config_bits2 & 36690075Sobrien SMP_RG_SAVING_ZENABLED_SUP)); 36790075Sobrien 36890075Sobrien sbuf_printf(sb, "Maximum Number of Routed SAS Addresses: %d\n", 36990075Sobrien scsi_2btoul(response->max_num_routed_addrs)); 37090075Sobrien 37190075Sobrien sbuf_printf(sb, "Active Zone Manager SAS Address: 0x%016jx\n", 37290075Sobrien scsi_8btou64(response->active_zm_address)); 37390075Sobrien 37490075Sobrien sbuf_printf(sb, "Zone Inactivity Time Limit: %d\n", 37590075Sobrien scsi_2btoul(response->zone_lock_inact_time_limit)); 37690075Sobrien 37790075Sobrien sbuf_printf(sb, "First Enclosure Connector Element Index: %d\n", 37890075Sobrien response->first_encl_conn_el_index); 37990075Sobrien 38090075Sobrien sbuf_printf(sb, "Number of Enclosure Connector Element Indexes: %d\n", 38190075Sobrien response->num_encl_conn_el_indexes); 38290075Sobrien 38390075Sobrien sbuf_printf(sb, "Reduced Functionality: %s\n", 38490075Sobrien smp_yesno(response->reduced_functionality & 38590075Sobrien SMP_RG_REDUCED_FUNCTIONALITY)); 38690075Sobrien 38790075Sobrien sbuf_printf(sb, "Time to Reduced Functionality: %d\n", 38890075Sobrien response->time_to_reduced_func); 38990075Sobrien sbuf_printf(sb, "Initial Time to Reduced Functionality: %d\n", 39090075Sobrien response->initial_time_to_reduced_func); 39190075Sobrien sbuf_printf(sb, "Maximum Reduced Functionality Time: %d\n", 39290075Sobrien response->max_reduced_func_time); 39390075Sobrien 39490075Sobrien sbuf_printf(sb, "Last Self-Configuration Status Descriptor Index: %d\n", 39590075Sobrien scsi_2btoul(response->last_sc_stat_desc_index)); 39690075Sobrien 39790075Sobrien sbuf_printf(sb, "Maximum Number of Storated Self-Configuration " 39890075Sobrien "Status Descriptors: %d\n", 39990075Sobrien scsi_2btoul(response->max_sc_stat_descs)); 40090075Sobrien 40190075Sobrien sbuf_printf(sb, "Last Phy Event List Descriptor Index: %d\n", 40290075Sobrien scsi_2btoul(response->last_phy_evl_desc_index)); 40390075Sobrien 40490075Sobrien sbuf_printf(sb, "Maximum Number of Stored Phy Event List " 40590075Sobrien "Descriptors: %d\n", 40690075Sobrien scsi_2btoul(response->max_stored_pel_descs)); 40790075Sobrien 40890075Sobrien sbuf_printf(sb, "STP Reject to Open Limit: %d\n", 40990075Sobrien scsi_2btoul(response->stp_reject_to_open_limit)); 41090075Sobrien} 41190075Sobrien 41290075Sobrien/* 41390075Sobrien * Decode the SMP REPORT MANUFACTURER INFORMATION response. The format is 41490075Sobrien * current as of SPL Revision 7, but the parsing should be backward 41590075Sobrien * compatible for older versions of the spec. 41690075Sobrien */ 41790075Sobrienvoid 41890075Sobriensmp_report_manuf_info_sbuf(struct smp_report_manuf_info_response *response, 41990075Sobrien int response_len, struct sbuf *sb) 42090075Sobrien{ 42190075Sobrien char vendor[16], product[48], revision[16]; 42290075Sobrien char comp_vendor[16]; 42390075Sobrien 42490075Sobrien sbuf_printf(sb, "Report Manufacturer Information\n"); 42590075Sobrien sbuf_printf(sb, "Expander Change count: %d\n", 42690075Sobrien scsi_2btoul(response->expander_change_count)); 42790075Sobrien sbuf_printf(sb, "SAS 1.1 Format: %s\n", 42890075Sobrien smp_yesno(response->sas_11_format & SMP_RMI_SAS11_FORMAT)); 42990075Sobrien cam_strvis(vendor, response->vendor, sizeof(response->vendor), 43090075Sobrien sizeof(vendor)); 43190075Sobrien cam_strvis(product, response->product, sizeof(response->product), 43290075Sobrien sizeof(product)); 43390075Sobrien cam_strvis(revision, response->revision, sizeof(response->revision), 43490075Sobrien sizeof(revision)); 43590075Sobrien sbuf_printf(sb, "<%s %s %s>\n", vendor, product, revision); 43690075Sobrien 43790075Sobrien if ((response->sas_11_format & SMP_RMI_SAS11_FORMAT) == 0) { 43890075Sobrien uint8_t *curbyte; 43990075Sobrien int line_start, line_cursor; 44090075Sobrien 44190075Sobrien sbuf_printf(sb, "Vendor Specific Data:\n"); 44290075Sobrien 44390075Sobrien /* 44490075Sobrien * Print out the bytes roughly in the style of hd(1), but 44590075Sobrien * without the extra ASCII decoding. Hexadecimal line 44690075Sobrien * numbers on the left, and 16 bytes per line, with an 44790075Sobrien * extra space after the first 8 bytes. 44890075Sobrien * 44990075Sobrien * It would be nice if this sort of thing were available 45090075Sobrien * in a library routine. 45190075Sobrien */ 45290075Sobrien for (curbyte = (uint8_t *)&response->comp_vendor, line_start= 1, 45390075Sobrien line_cursor = 0; curbyte < (uint8_t *)&response->crc; 45490075Sobrien curbyte++, line_cursor++) { 45590075Sobrien if (line_start != 0) { 45690075Sobrien sbuf_printf(sb, "%08lx ", 45790075Sobrien (unsigned long)(curbyte - 45890075Sobrien (uint8_t *)response)); 45990075Sobrien line_start = 0; 46090075Sobrien line_cursor = 0; 46190075Sobrien } 46290075Sobrien sbuf_printf(sb, "%02x", *curbyte); 46390075Sobrien 46490075Sobrien if (line_cursor == 15) { 46590075Sobrien sbuf_printf(sb, "\n"); 46690075Sobrien line_start = 1; 46790075Sobrien } else 46890075Sobrien sbuf_printf(sb, " %s", (line_cursor == 7) ? 46990075Sobrien " " : ""); 47090075Sobrien } 47190075Sobrien if (line_cursor != 16) 47290075Sobrien sbuf_printf(sb, "\n"); 47390075Sobrien return; 47490075Sobrien } 47590075Sobrien 47690075Sobrien cam_strvis(comp_vendor, response->comp_vendor, 47790075Sobrien sizeof(response->comp_vendor), sizeof(comp_vendor)); 47890075Sobrien sbuf_printf(sb, "Component Vendor: %s\n", comp_vendor); 47990075Sobrien sbuf_printf(sb, "Component ID: %#x\n", scsi_2btoul(response->comp_id)); 48090075Sobrien sbuf_printf(sb, "Component Revision: %#x\n", response->comp_revision); 48190075Sobrien sbuf_printf(sb, "Vendor Specific: 0x%016jx\n", 48290075Sobrien (uintmax_t)scsi_8btou64(response->vendor_specific)); 48390075Sobrien} 48490075Sobrien 48590075Sobrien/* 48690075Sobrien * Compose a SMP REPORT GENERAL request and put it into a CCB. This is 48790075Sobrien * current as of SPL Revision 7. 48890075Sobrien */ 48990075Sobrienvoid 49090075Sobriensmp_report_general(struct ccb_smpio *smpio, uint32_t retries, 49190075Sobrien void (*cbfcnp)(struct cam_periph *, union ccb *), 492117395Skan struct smp_report_general_request *request, int request_len, 493117395Skan uint8_t *response, int response_len, int long_response, 494117395Skan uint32_t timeout) 495117395Skan{ 496117395Skan cam_fill_smpio(smpio, 497117395Skan retries, 498117395Skan cbfcnp, 499117395Skan /*flags*/CAM_DIR_BOTH, 500117395Skan (uint8_t *)request, 501117395Skan request_len - SMP_CRC_LEN, 502117395Skan response, 503117395Skan response_len, 504117395Skan timeout); 505117395Skan 506117395Skan bzero(request, sizeof(*request)); 507117395Skan 508117395Skan request->frame_type = SMP_FRAME_TYPE_REQUEST; 509117395Skan request->function = SMP_FUNC_REPORT_GENERAL; 510117395Skan request->response_len = long_response ? SMP_RG_RESPONSE_LEN : 0; 511117395Skan request->request_len = 0; 512117395Skan} 513117395Skan 514117395Skan/* 515117395Skan * Compose a SMP DISCOVER request and put it into a CCB. This is current 516117395Skan * as of SPL Revision 7. 517117395Skan */ 518117395Skanvoid 519117395Skansmp_discover(struct ccb_smpio *smpio, uint32_t retries, 520117395Skan void (*cbfcnp)(struct cam_periph *, union ccb *), 521117395Skan struct smp_discover_request *request, int request_len, 522117395Skan uint8_t *response, int response_len, int long_response, 523117395Skan int ignore_zone_group, int phy, uint32_t timeout) 524117395Skan{ 525117395Skan cam_fill_smpio(smpio, 526117395Skan retries, 527117395Skan cbfcnp, 528117395Skan /*flags*/CAM_DIR_BOTH, 529117395Skan (uint8_t *)request, 530117395Skan request_len - SMP_CRC_LEN, 531117395Skan response, 532117395Skan response_len, 533117395Skan timeout); 534117395Skan 535117395Skan bzero(request, sizeof(*request)); 536117395Skan request->frame_type = SMP_FRAME_TYPE_REQUEST; 537117395Skan request->function = SMP_FUNC_DISCOVER; 538117395Skan request->response_len = long_response ? SMP_DIS_RESPONSE_LEN : 0; 539117395Skan request->request_len = long_response ? SMP_DIS_REQUEST_LEN : 0; 540117395Skan if (ignore_zone_group != 0) 541117395Skan request->ignore_zone_group |= SMP_DIS_IGNORE_ZONE_GROUP; 542117395Skan request->phy = phy; 543117395Skan} 544117395Skan 545117395Skan/* 546117395Skan * Compose a SMP REPORT MANUFACTURER INFORMATION request and put it into a 547117395Skan * CCB. This is current as of SPL Revision 7. 548117395Skan */ 549117395Skanvoid 550117395Skansmp_report_manuf_info(struct ccb_smpio *smpio, uint32_t retries, 551117395Skan void (*cbfcnp)(struct cam_periph *, union ccb *), 552117395Skan struct smp_report_manuf_info_request *request, 553117395Skan int request_len, uint8_t *response, int response_len, 554117395Skan int long_response, uint32_t timeout) 555117395Skan{ 556117395Skan cam_fill_smpio(smpio, 557117395Skan retries, 558117395Skan cbfcnp, 559117395Skan /*flags*/CAM_DIR_BOTH, 560117395Skan (uint8_t *)request, 561117395Skan request_len - SMP_CRC_LEN, 562117395Skan response, 563117395Skan response_len, 564117395Skan timeout); 565117395Skan 566117395Skan bzero(request, sizeof(*request)); 567117395Skan 56890075Sobrien request->frame_type = SMP_FRAME_TYPE_REQUEST; 56990075Sobrien request->function = SMP_FUNC_REPORT_MANUF_INFO; 57090075Sobrien request->response_len = long_response ? SMP_RMI_RESPONSE_LEN : 0; 57190075Sobrien request->request_len = long_response ? SMP_RMI_REQUEST_LEN : 0; 57290075Sobrien} 57390075Sobrien 57490075Sobrien/* 57590075Sobrien * Compose a SMP PHY CONTROL request and put it into a CCB. This is 57690075Sobrien * current as of SPL Revision 7. 57790075Sobrien */ 57890075Sobrienvoid 57990075Sobriensmp_phy_control(struct ccb_smpio *smpio, uint32_t retries, 58090075Sobrien void (*cbfcnp)(struct cam_periph *, union ccb *), 58190075Sobrien struct smp_phy_control_request *request, int request_len, 58290075Sobrien uint8_t *response, int response_len, int long_response, 58390075Sobrien uint32_t expected_exp_change_count, int phy, int phy_op, 58490075Sobrien int update_pp_timeout_val, uint64_t attached_device_name, 58590075Sobrien int prog_min_prl, int prog_max_prl, int slumber_partial, 58690075Sobrien int pp_timeout_value, uint32_t timeout) 58790075Sobrien{ 58890075Sobrien cam_fill_smpio(smpio, 58990075Sobrien retries, 59090075Sobrien cbfcnp, 59196263Sobrien /*flags*/CAM_DIR_BOTH, 59290075Sobrien (uint8_t *)request, 59390075Sobrien request_len - SMP_CRC_LEN, 59490075Sobrien response, 59590075Sobrien response_len, 59690075Sobrien timeout); 59790075Sobrien 59890075Sobrien bzero(request, sizeof(*request)); 59990075Sobrien 60090075Sobrien request->frame_type = SMP_FRAME_TYPE_REQUEST; 60190075Sobrien request->function = SMP_FUNC_PHY_CONTROL; 60290075Sobrien request->response_len = long_response ? SMP_PC_RESPONSE_LEN : 0; 60390075Sobrien request->request_len = long_response ? SMP_PC_REQUEST_LEN : 0; 60490075Sobrien scsi_ulto2b(expected_exp_change_count, request->expected_exp_chg_cnt); 60590075Sobrien request->phy = phy; 60690075Sobrien request->phy_operation = phy_op; 60790075Sobrien 60890075Sobrien if (update_pp_timeout_val != 0) 60990075Sobrien request->update_pp_timeout |= SMP_PC_UPDATE_PP_TIMEOUT; 61090075Sobrien 61190075Sobrien scsi_u64to8b(attached_device_name, request->attached_device_name); 61290075Sobrien request->prog_min_phys_link_rate = (prog_min_prl << 61390075Sobrien SMP_PC_PROG_MIN_PL_RATE_SHIFT) & SMP_PC_PROG_MIN_PL_RATE_MASK; 61490075Sobrien request->prog_max_phys_link_rate = (prog_max_prl << 61590075Sobrien SMP_PC_PROG_MAX_PL_RATE_SHIFT) & SMP_PC_PROG_MAX_PL_RATE_MASK; 61690075Sobrien request->config_bits0 = slumber_partial; 61790075Sobrien request->pp_timeout_value = pp_timeout_value; 61890075Sobrien} 61990075Sobrien 62090075Sobrien