1216088Sken/*- 2216088Sken * Copyright (c) 2010 Spectra Logic Corporation 3216088Sken * All rights reserved. 4216088Sken * 5216088Sken * Redistribution and use in source and binary forms, with or without 6216088Sken * modification, are permitted provided that the following conditions 7216088Sken * are met: 8216088Sken * 1. Redistributions of source code must retain the above copyright 9216088Sken * notice, this list of conditions, and the following disclaimer, 10216088Sken * without modification. 11216088Sken * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12216088Sken * substantially similar to the "NO WARRANTY" disclaimer below 13216088Sken * ("Disclaimer") and any redistribution must be conditioned upon 14216088Sken * including a substantially similar Disclaimer requirement for further 15216088Sken * binary redistribution. 16216088Sken * 17216088Sken * NO WARRANTY 18216088Sken * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19216088Sken * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20216088Sken * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21216088Sken * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22216088Sken * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23216088Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24216088Sken * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25216088Sken * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26216088Sken * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27216088Sken * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28216088Sken * POSSIBILITY OF SUCH DAMAGES. 29216088Sken * 30216088Sken * $Id: //depot/users/kenm/FreeBSD-test/sys/cam/scsi/smp_all.c#4 $ 31216088Sken */ 32216088Sken 33216088Sken/* 34216088Sken * Serial Management Protocol helper functions. 35216088Sken */ 36216088Sken 37216088Sken#include <sys/cdefs.h> 38216088Sken__FBSDID("$FreeBSD$"); 39216088Sken 40216088Sken#include <sys/param.h> 41216088Sken#include <sys/types.h> 42216088Sken#ifdef _KERNEL 43216088Sken#include <sys/systm.h> 44216088Sken#include <sys/libkern.h> 45216088Sken#include <sys/kernel.h> 46216088Sken#else /* _KERNEL */ 47216088Sken#include <errno.h> 48216088Sken#include <stdio.h> 49216088Sken#include <stdlib.h> 50216088Sken#include <string.h> 51216088Sken#include <inttypes.h> 52216088Sken#endif /* _KERNEL */ 53216088Sken 54216088Sken#include <cam/cam.h> 55216088Sken#include <cam/cam_ccb.h> 56216088Sken#include <cam/cam_xpt.h> 57216088Sken#include <cam/scsi/smp_all.h> 58216088Sken#include <sys/sbuf.h> 59216088Sken 60216088Sken#ifndef _KERNEL 61216088Sken#include <camlib.h> 62216088Sken#endif 63216088Sken 64216088Skenstatic char *smp_yesno(int val); 65216088Sken 66216088Skenstatic char * 67216088Skensmp_yesno(int val) 68216088Sken{ 69216088Sken char *str; 70216088Sken 71216088Sken if (val) 72216088Sken str = "Yes"; 73216088Sken else 74216088Sken str = "No"; 75216088Sken 76216088Sken return (str); 77216088Sken} 78216088Sken 79216088Skenstruct smp_error_table_entry { 80216088Sken uint8_t function_result; 81216088Sken const char *desc; 82216088Sken}; 83216088Sken 84216088Sken/* List current as of SPL Revision 7 */ 85216088Skenstatic struct smp_error_table_entry smp_error_table[] = { 86216088Sken {SMP_FR_ACCEPTED, "SMP Function Accepted"}, 87216088Sken {SMP_FR_UNKNOWN_FUNC, "Unknown SMP Function"}, 88216088Sken {SMP_FR_FUNCTION_FAILED, "SMP Function Failed"}, 89216088Sken {SMP_FR_INVALID_REQ_FRAME_LEN, "Invalid Request Frame Length"}, 90216088Sken {SMP_FR_INVALID_EXP_CHG_CNT, "Invalid Expander Change Count"}, 91216088Sken {SMP_FR_BUSY, "Busy"}, 92216088Sken {SMP_FR_INCOMPLETE_DESC_LIST, "Incomplete Descriptor List"}, 93216088Sken {SMP_FR_PHY_DOES_NOT_EXIST, "Phy Does Not Exist"}, 94216088Sken {SMP_FR_INDEX_DOES_NOT_EXIST, "Index Does Not Exist"}, 95216088Sken {SMP_FR_PHY_DOES_NOT_SUP_SATA, "Phy Does Not Support SATA"}, 96216088Sken {SMP_FR_UNKNOWN_PHY_OP, "Unknown Phy Operation"}, 97216088Sken {SMP_FR_UNKNOWN_PHY_TEST_FUNC, "Unknown Phy Test Function"}, 98216088Sken {SMP_FR_PHY_TEST_FUNC_INPROG, "Phy Test Function In Progress"}, 99216088Sken {SMP_FR_PHY_VACANT, "Phy Vacant"}, 100216088Sken {SMP_FR_UNKNOWN_PHY_EVENT_SRC, "Unknown Phy Event Source"}, 101216088Sken {SMP_FR_UNKNOWN_DESC_TYPE, "Unknown Descriptor Type"}, 102216088Sken {SMP_FR_UNKNOWN_PHY_FILTER, "Unknown Phy Filter"}, 103216088Sken {SMP_FR_AFFILIATION_VIOLATION, "Affiliation Violation"}, 104216088Sken {SMP_FR_SMP_ZONE_VIOLATION, "SMP Zone Violation"}, 105216088Sken {SMP_FR_NO_MGMT_ACCESS_RIGHTS, "No Management Access Rights"}, 106216088Sken {SMP_FR_UNKNOWN_ED_ZONING_VAL, "Unknown Enable Disable Zoning Value"}, 107216088Sken {SMP_FR_ZONE_LOCK_VIOLATION, "Zone Lock Violation"}, 108216088Sken {SMP_FR_NOT_ACTIVATED, "Not Activated"}, 109216088Sken {SMP_FR_ZG_OUT_OF_RANGE, "Zone Group Out of Range"}, 110216088Sken {SMP_FR_NO_PHYS_PRESENCE, "No Physical Presence"}, 111216088Sken {SMP_FR_SAVING_NOT_SUP, "Saving Not Supported"}, 112216088Sken {SMP_FR_SRC_ZONE_DNE, "Source Zone Group Does Not Exist"}, 113216088Sken {SMP_FR_DISABLED_PWD_NOT_SUP, "Disabled Password Not Supported"} 114216088Sken}; 115216088Sken 116216088Skenconst char * 117216088Skensmp_error_desc(int function_result) 118216088Sken{ 119216088Sken int i; 120216088Sken 121216088Sken for (i = 0; i < (sizeof(smp_error_table)/sizeof(smp_error_table[0])); 122216088Sken i++){ 123216088Sken if (function_result == smp_error_table[i].function_result) 124216088Sken return (smp_error_table[i].desc); 125216088Sken } 126216088Sken return ("Reserved Function Result"); 127216088Sken} 128216088Sken 129216088Sken/* List current as of SPL Revision 7 */ 130216088Skenstruct smp_cmd_table_entry { 131216088Sken uint8_t cmd_num; 132216088Sken const char *desc; 133216088Sken} smp_cmd_table[] = { 134216088Sken {SMP_FUNC_REPORT_GENERAL, "REPORT GENERAL"}, 135216088Sken {SMP_FUNC_REPORT_MANUF_INFO, "REPORT MANUFACTURER INFORMATION"}, 136216088Sken {SMP_FUNC_REPORT_SC_STATUS, "REPORT SELF-CONFIGURATION STATUS"}, 137216088Sken {SMP_FUNC_REPORT_ZONE_PERM_TBL, "REPORT ZONE PERMISSION TABLE"}, 138216088Sken {SMP_FUNC_REPORT_BROADCAST, "REPORT BROADCAST"}, 139216088Sken {SMP_FUNC_DISCOVER, "DISCOVER"}, 140216088Sken {SMP_FUNC_REPORT_PHY_ERR_LOG, "REPORT PHY ERROR LOG"}, 141216088Sken {SMP_FUNC_REPORT_PHY_SATA, "REPORT PHY SATA"}, 142216088Sken {SMP_FUNC_REPORT_ROUTE_INFO, "REPORT ROUTE INFORMATION"}, 143216088Sken {SMP_FUNC_REPORT_PHY_EVENT, "REPORT PHY EVENT"}, 144216088Sken {SMP_FUNC_DISCOVER_LIST, "DISCOVER LIST"}, 145216088Sken {SMP_FUNC_REPORT_PHY_EVENT_LIST, "REPORT PHY EVENT LIST"}, 146216088Sken {SMP_FUNC_REPORT_EXP_RTL, "REPORT EXPANDER ROUTE TABLE LIST"}, 147216088Sken {SMP_FUNC_CONFIG_GENERAL, "CONFIGURE GENERAL"}, 148216088Sken {SMP_FUNC_ENABLE_DISABLE_ZONING, "ENABLE DISABLE ZONING"}, 149216088Sken {SMP_FUNC_ZONED_BROADCAST, "ZONED BROADCAST"}, 150216088Sken {SMP_FUNC_ZONE_LOCK, "ZONE LOCK"}, 151216088Sken {SMP_FUNC_ZONE_ACTIVATE, "ZONE ACTIVATE"}, 152216088Sken {SMP_FUNC_ZONE_UNLOCK, "ZONE UNLOCK"}, 153216088Sken {SMP_FUNC_CONFIG_ZM_PWD, "CONFIGURE ZONE MANAGER PASSWORD"}, 154216088Sken {SMP_FUNC_CONFIG_ZONE_PHY_INFO, "CONFIGURE ZONE PHY INFORMATION"}, 155216088Sken {SMP_FUNC_CONFIG_ZONE_PERM_TBL, "CONFIGURE ZONE PERMISSION TABLE"}, 156216088Sken {SMP_FUNC_CONFIG_ROUTE_INFO, "CONFIGURE ROUTE INFORMATION"}, 157216088Sken {SMP_FUNC_PHY_CONTROL, "PHY CONTROL"}, 158216088Sken {SMP_FUNC_PHY_TEST_FUNC, "PHY TEST FUNCTION"}, 159216088Sken {SMP_FUNC_CONFIG_PHY_EVENT, "CONFIGURE PHY EVENT"} 160216088Sken}; 161216088Sken 162216088Skenconst char * 163216088Skensmp_command_desc(uint8_t cmd_num) 164216088Sken{ 165216088Sken int i; 166216088Sken 167216088Sken for (i = 0; i < (sizeof(smp_cmd_table)/sizeof(smp_cmd_table[0])) && 168216088Sken smp_cmd_table[i].cmd_num <= cmd_num; i++) { 169216088Sken if (cmd_num == smp_cmd_table[i].cmd_num) 170216088Sken return (smp_cmd_table[i].desc); 171216088Sken } 172216088Sken 173216088Sken /* 174216088Sken * 0x40 to 0x7f and 0xc0 to 0xff are the vendor specific SMP 175216088Sken * command ranges. 176216088Sken */ 177216088Sken if (((cmd_num >= 0x40) && (cmd_num <= 0x7f)) 178216088Sken || (cmd_num >= 0xc0)) { 179216088Sken return ("Vendor Specific SMP Command"); 180216088Sken } else { 181216088Sken return ("Unknown SMP Command"); 182216088Sken } 183216088Sken} 184216088Sken 185216088Sken/* 186216088Sken * Decode a SMP request buffer into a string of hexadecimal numbers. 187216088Sken * 188216088Sken * smp_request: SMP request 189216088Sken * request_len: length of the SMP request buffer, may be reduced if the 190216088Sken * caller only wants part of the buffer printed 191216088Sken * sb: sbuf(9) buffer 192216088Sken * line_prefix: prefix for new lines, or an empty string ("") 193216088Sken * first_line_len: length left on first line 194216088Sken * line_len: total length of subsequent lines, 0 for no additional lines 195216088Sken * if there are no additional lines, first line will get ... 196216088Sken * at the end if there is additional data 197216088Sken */ 198216088Skenvoid 199216088Skensmp_command_decode(uint8_t *smp_request, int request_len, struct sbuf *sb, 200216088Sken char *line_prefix, int first_line_len, int line_len) 201216088Sken{ 202216088Sken int i, cur_len; 203216088Sken 204216088Sken for (i = 0, cur_len = first_line_len; i < request_len; i++) { 205216088Sken /* 206216088Sken * Each byte takes 3 characters. As soon as we go less 207216088Sken * than 6 (meaning we have at least 3 and at most 5 208216088Sken * characters left), check to see whether the subsequent 209216088Sken * line length (line_len) is long enough to bother with. 210216088Sken * If the user set it to 0, or some other length that isn't 211216088Sken * enough to hold at least the prefix and one byte, put ... 212216088Sken * on the first line to indicate that there is more data 213216088Sken * and bail out. 214216088Sken */ 215216088Sken if ((cur_len < 6) 216216088Sken && (line_len < (strlen(line_prefix) + 3))) { 217216088Sken sbuf_printf(sb, "..."); 218216088Sken return; 219216088Sken } 220216088Sken if (cur_len < 3) { 221216088Sken sbuf_printf(sb, "\n%s", line_prefix); 222216088Sken cur_len = line_len - strlen(line_prefix); 223216088Sken } 224216088Sken sbuf_printf(sb, "%02x ", smp_request[i]); 225216088Sken cur_len = cur_len - 3; 226216088Sken } 227216088Sken} 228216088Sken 229216088Skenvoid 230216088Skensmp_command_sbuf(struct ccb_smpio *smpio, struct sbuf *sb, 231216088Sken char *line_prefix, int first_line_len, int line_len) 232216088Sken{ 233216088Sken sbuf_printf(sb, "%s. ", smp_command_desc(smpio->smp_request[1])); 234216088Sken 235216088Sken /* 236216088Sken * Acccount for the command description and the period and space 237216088Sken * after the command description. 238216088Sken */ 239216088Sken first_line_len -= strlen(smp_command_desc(smpio->smp_request[1])) + 2; 240216088Sken 241216088Sken smp_command_decode(smpio->smp_request, smpio->smp_request_len, sb, 242216088Sken line_prefix, first_line_len, line_len); 243216088Sken} 244216088Sken 245216088Sken/* 246216088Sken * Print SMP error output. For userland commands, we need the cam_device 247216088Sken * structure so we can get the path information from the CCB. 248216088Sken */ 249216088Sken#ifdef _KERNEL 250216088Skenvoid 251216088Skensmp_error_sbuf(struct ccb_smpio *smpio, struct sbuf *sb) 252216088Sken#else /* !_KERNEL*/ 253216088Skenvoid 254216088Skensmp_error_sbuf(struct cam_device *device, struct ccb_smpio *smpio, 255216088Sken struct sbuf *sb) 256216088Sken#endif /* _KERNEL/!_KERNEL */ 257216088Sken{ 258216088Sken char path_str[64]; 259216088Sken 260216088Sken#ifdef _KERNEL 261216088Sken xpt_path_string(smpio->ccb_h.path, path_str, sizeof(path_str)); 262216088Sken#else 263216088Sken cam_path_string(device, path_str, sizeof(path_str)); 264216088Sken#endif 265216088Sken smp_command_sbuf(smpio, sb, path_str, 80 - strlen(path_str), 80); 266216088Sken sbuf_printf(sb, "\n"); 267216088Sken 268216088Sken sbuf_cat(sb, path_str); 269216088Sken sbuf_printf(sb, "SMP Error: %s (0x%x)\n", 270216088Sken smp_error_desc(smpio->smp_response[2]), 271216088Sken smpio->smp_response[2]); 272216088Sken} 273216088Sken 274216088Sken/* 275216088Sken * Decode the SMP REPORT GENERAL response. The format is current as of SPL 276216088Sken * Revision 7, but the parsing should be backward compatible for older 277216088Sken * versions of the spec. 278216088Sken */ 279216088Skenvoid 280216088Skensmp_report_general_sbuf(struct smp_report_general_response *response, 281216088Sken int response_len, struct sbuf *sb) 282216088Sken{ 283216088Sken sbuf_printf(sb, "Report General\n"); 284216088Sken sbuf_printf(sb, "Response Length: %d words (%d bytes)\n", 285216088Sken response->response_len, 286216088Sken response->response_len * SMP_WORD_LEN); 287216088Sken sbuf_printf(sb, "Expander Change Count: %d\n", 288216088Sken scsi_2btoul(response->expander_change_count)); 289216088Sken sbuf_printf(sb, "Expander Route Indexes: %d\n", 290216088Sken scsi_2btoul(response->expander_route_indexes)); 291216088Sken sbuf_printf(sb, "Long Response: %s\n", 292216088Sken smp_yesno(response->long_response & 293216088Sken SMP_RG_LONG_RESPONSE)); 294216088Sken sbuf_printf(sb, "Number of Phys: %d\n", response->num_phys); 295216088Sken sbuf_printf(sb, "Table to Table Supported: %s\n", 296216088Sken smp_yesno(response->config_bits0 & 297216088Sken SMP_RG_TABLE_TO_TABLE_SUP)); 298216088Sken sbuf_printf(sb, "Zone Configuring: %s\n", 299216088Sken smp_yesno(response->config_bits0 & 300216088Sken SMP_RG_ZONE_CONFIGURING)); 301216088Sken sbuf_printf(sb, "Self Configuring: %s\n", 302216088Sken smp_yesno(response->config_bits0 & 303216088Sken SMP_RG_SELF_CONFIGURING)); 304216088Sken sbuf_printf(sb, "STP Continue AWT: %s\n", 305216088Sken smp_yesno(response->config_bits0 & 306216088Sken SMP_RG_STP_CONTINUE_AWT)); 307216088Sken sbuf_printf(sb, "Open Reject Retry Supported: %s\n", 308216088Sken smp_yesno(response->config_bits0 & 309216088Sken SMP_RG_OPEN_REJECT_RETRY_SUP)); 310216088Sken sbuf_printf(sb, "Configures Others: %s\n", 311216088Sken smp_yesno(response->config_bits0 & 312216088Sken SMP_RG_CONFIGURES_OTHERS)); 313216088Sken sbuf_printf(sb, "Configuring: %s\n", 314216088Sken smp_yesno(response->config_bits0 & 315216088Sken SMP_RG_CONFIGURING)); 316216088Sken sbuf_printf(sb, "Externally Configurable Route Table: %s\n", 317216088Sken smp_yesno(response->config_bits0 & 318216088Sken SMP_RG_CONFIGURING)); 319216088Sken sbuf_printf(sb, "Enclosure Logical Identifier: 0x%016jx\n", 320216088Sken (uintmax_t)scsi_8btou64(response->encl_logical_id)); 321216088Sken 322216088Sken /* 323216088Sken * If the response->response_len is 0, then we don't have the 324216088Sken * extended information. Also, if the user didn't allocate enough 325216088Sken * space for the full request, don't try to parse it. 326216088Sken */ 327216088Sken if ((response->response_len == 0) 328216088Sken || (response_len < (sizeof(struct smp_report_general_response) - 329216088Sken sizeof(response->crc)))) 330216088Sken return; 331216088Sken 332216088Sken sbuf_printf(sb, "STP Bus Inactivity Time Limit: %d\n", 333216088Sken scsi_2btoul(response->stp_bus_inact_time_limit)); 334216088Sken sbuf_printf(sb, "STP Maximum Connect Time Limit: %d\n", 335216088Sken scsi_2btoul(response->stp_max_conn_time_limit)); 336216088Sken sbuf_printf(sb, "STP SMP I_T Nexus Loss Time: %d\n", 337216088Sken scsi_2btoul(response->stp_smp_it_nexus_loss_time)); 338216088Sken 339216088Sken sbuf_printf(sb, "Number of Zone Groups: %d\n", 340216088Sken (response->config_bits1 & SMP_RG_NUM_ZONE_GROUPS_MASK) >> 341216088Sken SMP_RG_NUM_ZONE_GROUPS_SHIFT); 342216088Sken sbuf_printf(sb, "Zone Locked: %s\n", 343216088Sken smp_yesno(response->config_bits1 & SMP_RG_ZONE_LOCKED)); 344216088Sken sbuf_printf(sb, "Physical Presence Supported: %s\n", 345216088Sken smp_yesno(response->config_bits1 & SMP_RG_PP_SUPPORTED)); 346216088Sken sbuf_printf(sb, "Physical Presence Asserted: %s\n", 347216088Sken smp_yesno(response->config_bits1 & SMP_RG_PP_ASSERTED)); 348216088Sken sbuf_printf(sb, "Zoning Supported: %s\n", 349216088Sken smp_yesno(response->config_bits1 & 350216088Sken SMP_RG_ZONING_SUPPORTED)); 351216088Sken sbuf_printf(sb, "Zoning Enabled: %s\n", 352216088Sken smp_yesno(response->config_bits1 & SMP_RG_ZONING_ENABLED)); 353216088Sken 354216088Sken sbuf_printf(sb, "Saving: %s\n", 355216088Sken smp_yesno(response->config_bits2 & SMP_RG_SAVING)); 356216088Sken sbuf_printf(sb, "Saving Zone Manager Password Supported: %s\n", 357216088Sken smp_yesno(response->config_bits2 & 358216088Sken SMP_RG_SAVING_ZM_PWD_SUP)); 359216088Sken sbuf_printf(sb, "Saving Zone Phy Information Supported: %s\n", 360216088Sken smp_yesno(response->config_bits2 & 361216088Sken SMP_RG_SAVING_PHY_INFO_SUP)); 362216088Sken sbuf_printf(sb, "Saving Zone Permission Table Supported: %s\n", 363216088Sken smp_yesno(response->config_bits2 & 364216088Sken SMP_RG_SAVING_ZPERM_TAB_SUP)); 365216088Sken sbuf_printf(sb, "Saving Zoning Enabled Supported: %s\n", 366216088Sken smp_yesno(response->config_bits2 & 367216088Sken SMP_RG_SAVING_ZENABLED_SUP)); 368216088Sken 369216088Sken sbuf_printf(sb, "Maximum Number of Routed SAS Addresses: %d\n", 370216088Sken scsi_2btoul(response->max_num_routed_addrs)); 371216088Sken 372216088Sken sbuf_printf(sb, "Active Zone Manager SAS Address: 0x%016jx\n", 373216088Sken scsi_8btou64(response->active_zm_address)); 374216088Sken 375216088Sken sbuf_printf(sb, "Zone Inactivity Time Limit: %d\n", 376216088Sken scsi_2btoul(response->zone_lock_inact_time_limit)); 377216088Sken 378216088Sken sbuf_printf(sb, "First Enclosure Connector Element Index: %d\n", 379216088Sken response->first_encl_conn_el_index); 380216088Sken 381216088Sken sbuf_printf(sb, "Number of Enclosure Connector Element Indexes: %d\n", 382216088Sken response->num_encl_conn_el_indexes); 383216088Sken 384216088Sken sbuf_printf(sb, "Reduced Functionality: %s\n", 385216088Sken smp_yesno(response->reduced_functionality & 386216088Sken SMP_RG_REDUCED_FUNCTIONALITY)); 387216088Sken 388216088Sken sbuf_printf(sb, "Time to Reduced Functionality: %d\n", 389216088Sken response->time_to_reduced_func); 390216088Sken sbuf_printf(sb, "Initial Time to Reduced Functionality: %d\n", 391216088Sken response->initial_time_to_reduced_func); 392216088Sken sbuf_printf(sb, "Maximum Reduced Functionality Time: %d\n", 393216088Sken response->max_reduced_func_time); 394216088Sken 395216088Sken sbuf_printf(sb, "Last Self-Configuration Status Descriptor Index: %d\n", 396216088Sken scsi_2btoul(response->last_sc_stat_desc_index)); 397216088Sken 398216088Sken sbuf_printf(sb, "Maximum Number of Storated Self-Configuration " 399216088Sken "Status Descriptors: %d\n", 400216088Sken scsi_2btoul(response->max_sc_stat_descs)); 401216088Sken 402216088Sken sbuf_printf(sb, "Last Phy Event List Descriptor Index: %d\n", 403216088Sken scsi_2btoul(response->last_phy_evl_desc_index)); 404216088Sken 405216088Sken sbuf_printf(sb, "Maximum Number of Stored Phy Event List " 406216088Sken "Descriptors: %d\n", 407216088Sken scsi_2btoul(response->max_stored_pel_descs)); 408216088Sken 409216088Sken sbuf_printf(sb, "STP Reject to Open Limit: %d\n", 410216088Sken scsi_2btoul(response->stp_reject_to_open_limit)); 411216088Sken} 412216088Sken 413216088Sken/* 414216088Sken * Decode the SMP REPORT MANUFACTURER INFORMATION response. The format is 415216088Sken * current as of SPL Revision 7, but the parsing should be backward 416216088Sken * compatible for older versions of the spec. 417216088Sken */ 418216088Skenvoid 419216088Skensmp_report_manuf_info_sbuf(struct smp_report_manuf_info_response *response, 420216088Sken int response_len, struct sbuf *sb) 421216088Sken{ 422216088Sken char vendor[16], product[48], revision[16]; 423216088Sken char comp_vendor[16]; 424216088Sken 425216088Sken sbuf_printf(sb, "Report Manufacturer Information\n"); 426216088Sken sbuf_printf(sb, "Expander Change count: %d\n", 427216088Sken scsi_2btoul(response->expander_change_count)); 428216088Sken sbuf_printf(sb, "SAS 1.1 Format: %s\n", 429216088Sken smp_yesno(response->sas_11_format & SMP_RMI_SAS11_FORMAT)); 430216088Sken cam_strvis(vendor, response->vendor, sizeof(response->vendor), 431216088Sken sizeof(vendor)); 432216088Sken cam_strvis(product, response->product, sizeof(response->product), 433216088Sken sizeof(product)); 434216088Sken cam_strvis(revision, response->revision, sizeof(response->revision), 435216088Sken sizeof(revision)); 436216088Sken sbuf_printf(sb, "<%s %s %s>\n", vendor, product, revision); 437216088Sken 438216088Sken if ((response->sas_11_format & SMP_RMI_SAS11_FORMAT) == 0) { 439216088Sken uint8_t *curbyte; 440216088Sken int line_start, line_cursor; 441216088Sken 442216088Sken sbuf_printf(sb, "Vendor Specific Data:\n"); 443216088Sken 444216088Sken /* 445216088Sken * Print out the bytes roughly in the style of hd(1), but 446216088Sken * without the extra ASCII decoding. Hexadecimal line 447216088Sken * numbers on the left, and 16 bytes per line, with an 448216088Sken * extra space after the first 8 bytes. 449216088Sken * 450216088Sken * It would be nice if this sort of thing were available 451216088Sken * in a library routine. 452216088Sken */ 453216088Sken for (curbyte = (uint8_t *)&response->comp_vendor, line_start= 1, 454216088Sken line_cursor = 0; curbyte < (uint8_t *)&response->crc; 455216088Sken curbyte++, line_cursor++) { 456216088Sken if (line_start != 0) { 457216088Sken sbuf_printf(sb, "%08lx ", 458216088Sken (unsigned long)(curbyte - 459216088Sken (uint8_t *)response)); 460216088Sken line_start = 0; 461216088Sken line_cursor = 0; 462216088Sken } 463216088Sken sbuf_printf(sb, "%02x", *curbyte); 464216088Sken 465216088Sken if (line_cursor == 15) { 466216088Sken sbuf_printf(sb, "\n"); 467216088Sken line_start = 1; 468216088Sken } else 469216088Sken sbuf_printf(sb, " %s", (line_cursor == 7) ? 470216088Sken " " : ""); 471216088Sken } 472216088Sken if (line_cursor != 16) 473216088Sken sbuf_printf(sb, "\n"); 474216088Sken return; 475216088Sken } 476216088Sken 477216088Sken cam_strvis(comp_vendor, response->comp_vendor, 478216088Sken sizeof(response->comp_vendor), sizeof(comp_vendor)); 479216088Sken sbuf_printf(sb, "Component Vendor: %s\n", comp_vendor); 480216088Sken sbuf_printf(sb, "Component ID: %#x\n", scsi_2btoul(response->comp_id)); 481216088Sken sbuf_printf(sb, "Component Revision: %#x\n", response->comp_revision); 482216088Sken sbuf_printf(sb, "Vendor Specific: 0x%016jx\n", 483216088Sken (uintmax_t)scsi_8btou64(response->vendor_specific)); 484216088Sken} 485216088Sken 486216088Sken/* 487216088Sken * Compose a SMP REPORT GENERAL request and put it into a CCB. This is 488216088Sken * current as of SPL Revision 7. 489216088Sken */ 490216088Skenvoid 491216088Skensmp_report_general(struct ccb_smpio *smpio, uint32_t retries, 492216088Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 493216088Sken struct smp_report_general_request *request, int request_len, 494216088Sken uint8_t *response, int response_len, int long_response, 495216088Sken uint32_t timeout) 496216088Sken{ 497216088Sken cam_fill_smpio(smpio, 498216088Sken retries, 499216088Sken cbfcnp, 500216088Sken /*flags*/CAM_DIR_BOTH, 501216088Sken (uint8_t *)request, 502216088Sken request_len - SMP_CRC_LEN, 503216088Sken response, 504216088Sken response_len, 505216088Sken timeout); 506216088Sken 507216088Sken bzero(request, sizeof(*request)); 508216088Sken 509216088Sken request->frame_type = SMP_FRAME_TYPE_REQUEST; 510216088Sken request->function = SMP_FUNC_REPORT_GENERAL; 511216088Sken request->response_len = long_response ? SMP_RG_RESPONSE_LEN : 0; 512216088Sken request->request_len = 0; 513216088Sken} 514216088Sken 515216088Sken/* 516216088Sken * Compose a SMP DISCOVER request and put it into a CCB. This is current 517216088Sken * as of SPL Revision 7. 518216088Sken */ 519216088Skenvoid 520216088Skensmp_discover(struct ccb_smpio *smpio, uint32_t retries, 521216088Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 522216088Sken struct smp_discover_request *request, int request_len, 523216088Sken uint8_t *response, int response_len, int long_response, 524216088Sken int ignore_zone_group, int phy, uint32_t timeout) 525216088Sken{ 526216088Sken cam_fill_smpio(smpio, 527216088Sken retries, 528216088Sken cbfcnp, 529216088Sken /*flags*/CAM_DIR_BOTH, 530216088Sken (uint8_t *)request, 531216088Sken request_len - SMP_CRC_LEN, 532216088Sken response, 533216088Sken response_len, 534216088Sken timeout); 535216088Sken 536216088Sken bzero(request, sizeof(*request)); 537216088Sken request->frame_type = SMP_FRAME_TYPE_REQUEST; 538216088Sken request->function = SMP_FUNC_DISCOVER; 539216088Sken request->response_len = long_response ? SMP_DIS_RESPONSE_LEN : 0; 540216088Sken request->request_len = long_response ? SMP_DIS_REQUEST_LEN : 0; 541216088Sken if (ignore_zone_group != 0) 542216088Sken request->ignore_zone_group |= SMP_DIS_IGNORE_ZONE_GROUP; 543216088Sken request->phy = phy; 544216088Sken} 545216088Sken 546216088Sken/* 547216088Sken * Compose a SMP REPORT MANUFACTURER INFORMATION request and put it into a 548216088Sken * CCB. This is current as of SPL Revision 7. 549216088Sken */ 550216088Skenvoid 551216088Skensmp_report_manuf_info(struct ccb_smpio *smpio, uint32_t retries, 552216088Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 553216088Sken struct smp_report_manuf_info_request *request, 554216088Sken int request_len, uint8_t *response, int response_len, 555216088Sken int long_response, uint32_t timeout) 556216088Sken{ 557216088Sken cam_fill_smpio(smpio, 558216088Sken retries, 559216088Sken cbfcnp, 560216088Sken /*flags*/CAM_DIR_BOTH, 561216088Sken (uint8_t *)request, 562216088Sken request_len - SMP_CRC_LEN, 563216088Sken response, 564216088Sken response_len, 565216088Sken timeout); 566216088Sken 567216088Sken bzero(request, sizeof(*request)); 568216088Sken 569216088Sken request->frame_type = SMP_FRAME_TYPE_REQUEST; 570216088Sken request->function = SMP_FUNC_REPORT_MANUF_INFO; 571216088Sken request->response_len = long_response ? SMP_RMI_RESPONSE_LEN : 0; 572216088Sken request->request_len = long_response ? SMP_RMI_REQUEST_LEN : 0; 573216088Sken} 574216088Sken 575216088Sken/* 576216088Sken * Compose a SMP PHY CONTROL request and put it into a CCB. This is 577216088Sken * current as of SPL Revision 7. 578216088Sken */ 579216088Skenvoid 580216088Skensmp_phy_control(struct ccb_smpio *smpio, uint32_t retries, 581216088Sken void (*cbfcnp)(struct cam_periph *, union ccb *), 582216088Sken struct smp_phy_control_request *request, int request_len, 583216088Sken uint8_t *response, int response_len, int long_response, 584216088Sken uint32_t expected_exp_change_count, int phy, int phy_op, 585216088Sken int update_pp_timeout_val, uint64_t attached_device_name, 586216088Sken int prog_min_prl, int prog_max_prl, int slumber_partial, 587216088Sken int pp_timeout_value, uint32_t timeout) 588216088Sken{ 589216088Sken cam_fill_smpio(smpio, 590216088Sken retries, 591216088Sken cbfcnp, 592216088Sken /*flags*/CAM_DIR_BOTH, 593216088Sken (uint8_t *)request, 594216088Sken request_len - SMP_CRC_LEN, 595216088Sken response, 596216088Sken response_len, 597216088Sken timeout); 598216088Sken 599216088Sken bzero(request, sizeof(*request)); 600216088Sken 601216088Sken request->frame_type = SMP_FRAME_TYPE_REQUEST; 602216088Sken request->function = SMP_FUNC_PHY_CONTROL; 603216088Sken request->response_len = long_response ? SMP_PC_RESPONSE_LEN : 0; 604216088Sken request->request_len = long_response ? SMP_PC_REQUEST_LEN : 0; 605216088Sken scsi_ulto2b(expected_exp_change_count, request->expected_exp_chg_cnt); 606216088Sken request->phy = phy; 607216088Sken request->phy_operation = phy_op; 608216088Sken 609216088Sken if (update_pp_timeout_val != 0) 610216088Sken request->update_pp_timeout |= SMP_PC_UPDATE_PP_TIMEOUT; 611216088Sken 612216088Sken scsi_u64to8b(attached_device_name, request->attached_device_name); 613216088Sken request->prog_min_phys_link_rate = (prog_min_prl << 614216088Sken SMP_PC_PROG_MIN_PL_RATE_SHIFT) & SMP_PC_PROG_MIN_PL_RATE_MASK; 615216088Sken request->prog_max_phys_link_rate = (prog_max_prl << 616216088Sken SMP_PC_PROG_MAX_PL_RATE_SHIFT) & SMP_PC_PROG_MAX_PL_RATE_MASK; 617216088Sken request->config_bits0 = slumber_partial; 618216088Sken request->pp_timeout_value = pp_timeout_value; 619216088Sken} 620216088Sken 621