1 /*- 2 * Copyright (c) 2010 Spectra Logic Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * substantially similar to the "NO WARRANTY" disclaimer below 13 * ("Disclaimer") and any redistribution must be conditioned upon 14 * including a substantially similar Disclaimer requirement for further 15 * binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGES. 29 * 30 * $Id: //depot/users/kenm/FreeBSD-test/sys/cam/scsi/smp_all.c#4 $ 31 */ 32 33 /* 34 * Serial Management Protocol helper functions. 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/param.h> 41 #include <sys/types.h> 42 #ifdef _KERNEL 43 #include <sys/systm.h> 44 #include <sys/libkern.h> 45 #include <sys/kernel.h> 46 #else /* _KERNEL */ 47 #include <errno.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <inttypes.h> 52 #endif /* _KERNEL */ 53 54 #include <cam/cam.h> 55 #include <cam/cam_ccb.h> 56 #include <cam/cam_xpt.h> 57 #include <cam/scsi/smp_all.h> 58 #include <sys/sbuf.h> 59 60 #ifndef _KERNEL 61 #include <camlib.h> 62 #endif 63 64 static char *smp_yesno(int val); 65 66 static char * 67 smp_yesno(int val) 68 { 69 char *str; 70 71 if (val) 72 str = "Yes"; 73 else 74 str = "No"; 75 76 return (str); 77 } 78 79 struct smp_error_table_entry { 80 uint8_t function_result; 81 const char *desc; 82 }; 83 84 /* List current as of SPL Revision 7 */ 85 static struct smp_error_table_entry smp_error_table[] = { 86 {SMP_FR_ACCEPTED, "SMP Function Accepted"}, 87 {SMP_FR_UNKNOWN_FUNC, "Unknown SMP Function"}, 88 {SMP_FR_FUNCTION_FAILED, "SMP Function Failed"}, 89 {SMP_FR_INVALID_REQ_FRAME_LEN, "Invalid Request Frame Length"}, 90 {SMP_FR_INVALID_EXP_CHG_CNT, "Invalid Expander Change Count"}, 91 {SMP_FR_BUSY, "Busy"}, 92 {SMP_FR_INCOMPLETE_DESC_LIST, "Incomplete Descriptor List"}, 93 {SMP_FR_PHY_DOES_NOT_EXIST, "Phy Does Not Exist"}, 94 {SMP_FR_INDEX_DOES_NOT_EXIST, "Index Does Not Exist"}, 95 {SMP_FR_PHY_DOES_NOT_SUP_SATA, "Phy Does Not Support SATA"}, 96 {SMP_FR_UNKNOWN_PHY_OP, "Unknown Phy Operation"}, 97 {SMP_FR_UNKNOWN_PHY_TEST_FUNC, "Unknown Phy Test Function"}, 98 {SMP_FR_PHY_TEST_FUNC_INPROG, "Phy Test Function In Progress"}, 99 {SMP_FR_PHY_VACANT, "Phy Vacant"}, 100 {SMP_FR_UNKNOWN_PHY_EVENT_SRC, "Unknown Phy Event Source"}, 101 {SMP_FR_UNKNOWN_DESC_TYPE, "Unknown Descriptor Type"}, 102 {SMP_FR_UNKNOWN_PHY_FILTER, "Unknown Phy Filter"}, 103 {SMP_FR_AFFILIATION_VIOLATION, "Affiliation Violation"}, 104 {SMP_FR_SMP_ZONE_VIOLATION, "SMP Zone Violation"}, 105 {SMP_FR_NO_MGMT_ACCESS_RIGHTS, "No Management Access Rights"}, 106 {SMP_FR_UNKNOWN_ED_ZONING_VAL, "Unknown Enable Disable Zoning Value"}, 107 {SMP_FR_ZONE_LOCK_VIOLATION, "Zone Lock Violation"}, 108 {SMP_FR_NOT_ACTIVATED, "Not Activated"}, 109 {SMP_FR_ZG_OUT_OF_RANGE, "Zone Group Out of Range"}, 110 {SMP_FR_NO_PHYS_PRESENCE, "No Physical Presence"}, 111 {SMP_FR_SAVING_NOT_SUP, "Saving Not Supported"}, 112 {SMP_FR_SRC_ZONE_DNE, "Source Zone Group Does Not Exist"}, 113 {SMP_FR_DISABLED_PWD_NOT_SUP, "Disabled Password Not Supported"} 114 }; 115 116 const char * 117 smp_error_desc(int function_result) 118 { 119 int i; 120 121 for (i = 0; i < (sizeof(smp_error_table)/sizeof(smp_error_table[0])); 122 i++){ 123 if (function_result == smp_error_table[i].function_result) 124 return (smp_error_table[i].desc); 125 } 126 return ("Reserved Function Result"); 127 } 128 129 /* List current as of SPL Revision 7 */ 130 struct smp_cmd_table_entry { 131 uint8_t cmd_num; 132 const char *desc; 133 } smp_cmd_table[] = { 134 {SMP_FUNC_REPORT_GENERAL, "REPORT GENERAL"}, 135 {SMP_FUNC_REPORT_MANUF_INFO, "REPORT MANUFACTURER INFORMATION"}, 136 {SMP_FUNC_REPORT_SC_STATUS, "REPORT SELF-CONFIGURATION STATUS"}, 137 {SMP_FUNC_REPORT_ZONE_PERM_TBL, "REPORT ZONE PERMISSION TABLE"}, 138 {SMP_FUNC_REPORT_BROADCAST, "REPORT BROADCAST"}, 139 {SMP_FUNC_DISCOVER, "DISCOVER"}, 140 {SMP_FUNC_REPORT_PHY_ERR_LOG, "REPORT PHY ERROR LOG"}, 141 {SMP_FUNC_REPORT_PHY_SATA, "REPORT PHY SATA"}, 142 {SMP_FUNC_REPORT_ROUTE_INFO, "REPORT ROUTE INFORMATION"}, 143 {SMP_FUNC_REPORT_PHY_EVENT, "REPORT PHY EVENT"}, 144 {SMP_FUNC_DISCOVER_LIST, "DISCOVER LIST"}, 145 {SMP_FUNC_REPORT_PHY_EVENT_LIST, "REPORT PHY EVENT LIST"}, 146 {SMP_FUNC_REPORT_EXP_RTL, "REPORT EXPANDER ROUTE TABLE LIST"}, 147 {SMP_FUNC_CONFIG_GENERAL, "CONFIGURE GENERAL"}, 148 {SMP_FUNC_ENABLE_DISABLE_ZONING, "ENABLE DISABLE ZONING"}, 149 {SMP_FUNC_ZONED_BROADCAST, "ZONED BROADCAST"}, 150 {SMP_FUNC_ZONE_LOCK, "ZONE LOCK"}, 151 {SMP_FUNC_ZONE_ACTIVATE, "ZONE ACTIVATE"}, 152 {SMP_FUNC_ZONE_UNLOCK, "ZONE UNLOCK"}, 153 {SMP_FUNC_CONFIG_ZM_PWD, "CONFIGURE ZONE MANAGER PASSWORD"}, 154 {SMP_FUNC_CONFIG_ZONE_PHY_INFO, "CONFIGURE ZONE PHY INFORMATION"}, 155 {SMP_FUNC_CONFIG_ZONE_PERM_TBL, "CONFIGURE ZONE PERMISSION TABLE"}, 156 {SMP_FUNC_CONFIG_ROUTE_INFO, "CONFIGURE ROUTE INFORMATION"}, 157 {SMP_FUNC_PHY_CONTROL, "PHY CONTROL"}, 158 {SMP_FUNC_PHY_TEST_FUNC, "PHY TEST FUNCTION"}, 159 {SMP_FUNC_CONFIG_PHY_EVENT, "CONFIGURE PHY EVENT"} 160 }; 161 162 const char * 163 smp_command_desc(uint8_t cmd_num) 164 { 165 int i; 166 167 for (i = 0; i < (sizeof(smp_cmd_table)/sizeof(smp_cmd_table[0])) && 168 smp_cmd_table[i].cmd_num <= cmd_num; i++) { 169 if (cmd_num == smp_cmd_table[i].cmd_num) 170 return (smp_cmd_table[i].desc); 171 } 172 173 /* 174 * 0x40 to 0x7f and 0xc0 to 0xff are the vendor specific SMP 175 * command ranges. 176 */ 177 if (((cmd_num >= 0x40) && (cmd_num <= 0x7f)) 178 || (cmd_num >= 0xc0)) { 179 return ("Vendor Specific SMP Command"); 180 } else { 181 return ("Unknown SMP Command"); 182 } 183 } 184 185 /* 186 * Decode a SMP request buffer into a string of hexadecimal numbers. 187 * 188 * smp_request: SMP request 189 * request_len: length of the SMP request buffer, may be reduced if the 190 * caller only wants part of the buffer printed 191 * sb: sbuf(9) buffer 192 * line_prefix: prefix for new lines, or an empty string ("") 193 * first_line_len: length left on first line 194 * line_len: total length of subsequent lines, 0 for no additional lines 195 * if there are no additional lines, first line will get ... 196 * at the end if there is additional data 197 */ 198 void 199 smp_command_decode(uint8_t *smp_request, int request_len, struct sbuf *sb, 200 char *line_prefix, int first_line_len, int line_len) 201 { 202 int i, cur_len; 203 204 for (i = 0, cur_len = first_line_len; i < request_len; i++) { 205 /* 206 * Each byte takes 3 characters. As soon as we go less 207 * than 6 (meaning we have at least 3 and at most 5 208 * characters left), check to see whether the subsequent 209 * line length (line_len) is long enough to bother with. 210 * If the user set it to 0, or some other length that isn't 211 * enough to hold at least the prefix and one byte, put ... 212 * on the first line to indicate that there is more data 213 * and bail out. 214 */ 215 if ((cur_len < 6) 216 && (line_len < (strlen(line_prefix) + 3))) { 217 sbuf_printf(sb, "..."); 218 return; 219 } 220 if (cur_len < 3) { 221 sbuf_printf(sb, "\n%s", line_prefix); 222 cur_len = line_len - strlen(line_prefix); 223 } 224 sbuf_printf(sb, "%02x ", smp_request[i]); 225 cur_len = cur_len - 3; 226 } 227 } 228 229 void 230 smp_command_sbuf(struct ccb_smpio *smpio, struct sbuf *sb, 231 char *line_prefix, int first_line_len, int line_len) 232 { 233 sbuf_printf(sb, "%s. ", smp_command_desc(smpio->smp_request[1])); 234 235 /* 236 * Acccount for the command description and the period and space 237 * after the command description. 238 */ 239 first_line_len -= strlen(smp_command_desc(smpio->smp_request[1])) + 2; 240 241 smp_command_decode(smpio->smp_request, smpio->smp_request_len, sb, 242 line_prefix, first_line_len, line_len); 243 } 244 245 /* 246 * Print SMP error output. For userland commands, we need the cam_device 247 * structure so we can get the path information from the CCB. 248 */ 249 #ifdef _KERNEL 250 void 251 smp_error_sbuf(struct ccb_smpio *smpio, struct sbuf *sb) 252 #else /* !_KERNEL*/ 253 void 254 smp_error_sbuf(struct cam_device *device, struct ccb_smpio *smpio, 255 struct sbuf *sb) 256 #endif /* _KERNEL/!_KERNEL */ 257 { 258 char path_str[64]; 259 260 #ifdef _KERNEL 261 xpt_path_string(smpio->ccb_h.path, path_str, sizeof(path_str)); 262 #else 263 cam_path_string(device, path_str, sizeof(path_str)); 264 #endif 265 smp_command_sbuf(smpio, sb, path_str, 80 - strlen(path_str), 80); 266 sbuf_printf(sb, "\n"); 267 268 sbuf_cat(sb, path_str); 269 sbuf_printf(sb, "SMP Error: %s (0x%x)\n", 270 smp_error_desc(smpio->smp_response[2]), 271 smpio->smp_response[2]); 272 } 273 274 /* 275 * Decode the SMP REPORT GENERAL response. The format is current as of SPL 276 * Revision 7, but the parsing should be backward compatible for older 277 * versions of the spec. 278 */ 279 void 280 smp_report_general_sbuf(struct smp_report_general_response *response, 281 int response_len, struct sbuf *sb) 282 { 283 sbuf_printf(sb, "Report General\n"); 284 sbuf_printf(sb, "Response Length: %d words (%d bytes)\n", 285 response->response_len, 286 response->response_len * SMP_WORD_LEN); 287 sbuf_printf(sb, "Expander Change Count: %d\n", 288 scsi_2btoul(response->expander_change_count)); 289 sbuf_printf(sb, "Expander Route Indexes: %d\n", 290 scsi_2btoul(response->expander_route_indexes)); 291 sbuf_printf(sb, "Long Response: %s\n", 292 smp_yesno(response->long_response & 293 SMP_RG_LONG_RESPONSE)); 294 sbuf_printf(sb, "Number of Phys: %d\n", response->num_phys); 295 sbuf_printf(sb, "Table to Table Supported: %s\n", 296 smp_yesno(response->config_bits0 & 297 SMP_RG_TABLE_TO_TABLE_SUP)); 298 sbuf_printf(sb, "Zone Configuring: %s\n", 299 smp_yesno(response->config_bits0 & 300 SMP_RG_ZONE_CONFIGURING)); 301 sbuf_printf(sb, "Self Configuring: %s\n", 302 smp_yesno(response->config_bits0 & 303 SMP_RG_SELF_CONFIGURING)); 304 sbuf_printf(sb, "STP Continue AWT: %s\n", 305 smp_yesno(response->config_bits0 & 306 SMP_RG_STP_CONTINUE_AWT)); 307 sbuf_printf(sb, "Open Reject Retry Supported: %s\n", 308 smp_yesno(response->config_bits0 & 309 SMP_RG_OPEN_REJECT_RETRY_SUP)); 310 sbuf_printf(sb, "Configures Others: %s\n", 311 smp_yesno(response->config_bits0 & 312 SMP_RG_CONFIGURES_OTHERS)); 313 sbuf_printf(sb, "Configuring: %s\n", 314 smp_yesno(response->config_bits0 & 315 SMP_RG_CONFIGURING)); 316 sbuf_printf(sb, "Externally Configurable Route Table: %s\n", 317 smp_yesno(response->config_bits0 & 318 SMP_RG_CONFIGURING)); 319 sbuf_printf(sb, "Enclosure Logical Identifier: 0x%016jx\n", 320 (uintmax_t)scsi_8btou64(response->encl_logical_id)); 321 322 /* 323 * If the response->response_len is 0, then we don't have the 324 * extended information. Also, if the user didn't allocate enough 325 * space for the full request, don't try to parse it. 326 */ 327 if ((response->response_len == 0) 328 || (response_len < (sizeof(struct smp_report_general_response) - 329 sizeof(response->crc)))) 330 return; 331 332 sbuf_printf(sb, "STP Bus Inactivity Time Limit: %d\n", 333 scsi_2btoul(response->stp_bus_inact_time_limit)); 334 sbuf_printf(sb, "STP Maximum Connect Time Limit: %d\n", 335 scsi_2btoul(response->stp_max_conn_time_limit)); 336 sbuf_printf(sb, "STP SMP I_T Nexus Loss Time: %d\n", 337 scsi_2btoul(response->stp_smp_it_nexus_loss_time)); 338 339 sbuf_printf(sb, "Number of Zone Groups: %d\n", 340 (response->config_bits1 & SMP_RG_NUM_ZONE_GROUPS_MASK) >> 341 SMP_RG_NUM_ZONE_GROUPS_SHIFT); 342 sbuf_printf(sb, "Zone Locked: %s\n", 343 smp_yesno(response->config_bits1 & SMP_RG_ZONE_LOCKED)); 344 sbuf_printf(sb, "Physical Presence Supported: %s\n", 345 smp_yesno(response->config_bits1 & SMP_RG_PP_SUPPORTED)); 346 sbuf_printf(sb, "Physical Presence Asserted: %s\n", 347 smp_yesno(response->config_bits1 & SMP_RG_PP_ASSERTED)); 348 sbuf_printf(sb, "Zoning Supported: %s\n", 349 smp_yesno(response->config_bits1 & 350 SMP_RG_ZONING_SUPPORTED)); 351 sbuf_printf(sb, "Zoning Enabled: %s\n", 352 smp_yesno(response->config_bits1 & SMP_RG_ZONING_ENABLED)); 353 354 sbuf_printf(sb, "Saving: %s\n", 355 smp_yesno(response->config_bits2 & SMP_RG_SAVING)); 356 sbuf_printf(sb, "Saving Zone Manager Password Supported: %s\n", 357 smp_yesno(response->config_bits2 & 358 SMP_RG_SAVING_ZM_PWD_SUP)); 359 sbuf_printf(sb, "Saving Zone Phy Information Supported: %s\n", 360 smp_yesno(response->config_bits2 & 361 SMP_RG_SAVING_PHY_INFO_SUP)); 362 sbuf_printf(sb, "Saving Zone Permission Table Supported: %s\n", 363 smp_yesno(response->config_bits2 & 364 SMP_RG_SAVING_ZPERM_TAB_SUP)); 365 sbuf_printf(sb, "Saving Zoning Enabled Supported: %s\n", 366 smp_yesno(response->config_bits2 & 367 SMP_RG_SAVING_ZENABLED_SUP)); 368 369 sbuf_printf(sb, "Maximum Number of Routed SAS Addresses: %d\n", 370 scsi_2btoul(response->max_num_routed_addrs)); 371 372 sbuf_printf(sb, "Active Zone Manager SAS Address: 0x%016jx\n", 373 scsi_8btou64(response->active_zm_address)); 374 375 sbuf_printf(sb, "Zone Inactivity Time Limit: %d\n", 376 scsi_2btoul(response->zone_lock_inact_time_limit)); 377 378 sbuf_printf(sb, "First Enclosure Connector Element Index: %d\n", 379 response->first_encl_conn_el_index); 380 381 sbuf_printf(sb, "Number of Enclosure Connector Element Indexes: %d\n", 382 response->num_encl_conn_el_indexes); 383 384 sbuf_printf(sb, "Reduced Functionality: %s\n", 385 smp_yesno(response->reduced_functionality & 386 SMP_RG_REDUCED_FUNCTIONALITY)); 387 388 sbuf_printf(sb, "Time to Reduced Functionality: %d\n", 389 response->time_to_reduced_func); 390 sbuf_printf(sb, "Initial Time to Reduced Functionality: %d\n", 391 response->initial_time_to_reduced_func); 392 sbuf_printf(sb, "Maximum Reduced Functionality Time: %d\n", 393 response->max_reduced_func_time); 394 395 sbuf_printf(sb, "Last Self-Configuration Status Descriptor Index: %d\n", 396 scsi_2btoul(response->last_sc_stat_desc_index)); 397 398 sbuf_printf(sb, "Maximum Number of Storated Self-Configuration " 399 "Status Descriptors: %d\n", 400 scsi_2btoul(response->max_sc_stat_descs)); 401 402 sbuf_printf(sb, "Last Phy Event List Descriptor Index: %d\n", 403 scsi_2btoul(response->last_phy_evl_desc_index)); 404 405 sbuf_printf(sb, "Maximum Number of Stored Phy Event List " 406 "Descriptors: %d\n", 407 scsi_2btoul(response->max_stored_pel_descs)); 408 409 sbuf_printf(sb, "STP Reject to Open Limit: %d\n", 410 scsi_2btoul(response->stp_reject_to_open_limit)); 411 } 412 413 /* 414 * Decode the SMP REPORT MANUFACTURER INFORMATION response. The format is 415 * current as of SPL Revision 7, but the parsing should be backward 416 * compatible for older versions of the spec. 417 */ 418 void 419 smp_report_manuf_info_sbuf(struct smp_report_manuf_info_response *response, 420 int response_len, struct sbuf *sb) 421 { 422 char vendor[16], product[48], revision[16]; 423 char comp_vendor[16]; 424 425 sbuf_printf(sb, "Report Manufacturer Information\n"); 426 sbuf_printf(sb, "Expander Change count: %d\n", 427 scsi_2btoul(response->expander_change_count)); 428 sbuf_printf(sb, "SAS 1.1 Format: %s\n", 429 smp_yesno(response->sas_11_format & SMP_RMI_SAS11_FORMAT)); 430 cam_strvis(vendor, response->vendor, sizeof(response->vendor), 431 sizeof(vendor)); 432 cam_strvis(product, response->product, sizeof(response->product), 433 sizeof(product)); 434 cam_strvis(revision, response->revision, sizeof(response->revision), 435 sizeof(revision)); 436 sbuf_printf(sb, "<%s %s %s>\n", vendor, product, revision); 437 438 if ((response->sas_11_format & SMP_RMI_SAS11_FORMAT) == 0) { 439 uint8_t *curbyte; 440 int line_start, line_cursor; 441 442 sbuf_printf(sb, "Vendor Specific Data:\n"); 443 444 /* 445 * Print out the bytes roughly in the style of hd(1), but 446 * without the extra ASCII decoding. Hexadecimal line 447 * numbers on the left, and 16 bytes per line, with an 448 * extra space after the first 8 bytes. 449 * 450 * It would be nice if this sort of thing were available 451 * in a library routine. 452 */ 453 for (curbyte = (uint8_t *)&response->comp_vendor, line_start= 1, 454 line_cursor = 0; curbyte < (uint8_t *)&response->crc; 455 curbyte++, line_cursor++) { 456 if (line_start != 0) { 457 sbuf_printf(sb, "%08lx ", 458 (unsigned long)(curbyte - 459 (uint8_t *)response)); 460 line_start = 0; 461 line_cursor = 0; 462 } 463 sbuf_printf(sb, "%02x", *curbyte); 464 465 if (line_cursor == 15) { 466 sbuf_printf(sb, "\n"); 467 line_start = 1; 468 } else 469 sbuf_printf(sb, " %s", (line_cursor == 7) ? 470 " " : ""); 471 } 472 if (line_cursor != 16) 473 sbuf_printf(sb, "\n"); 474 return; 475 } 476 477 cam_strvis(comp_vendor, response->comp_vendor, 478 sizeof(response->comp_vendor), sizeof(comp_vendor)); 479 sbuf_printf(sb, "Component Vendor: %s\n", comp_vendor); 480 sbuf_printf(sb, "Component ID: %#x\n", scsi_2btoul(response->comp_id)); 481 sbuf_printf(sb, "Component Revision: %#x\n", response->comp_revision); 482 sbuf_printf(sb, "Vendor Specific: 0x%016jx\n", 483 (uintmax_t)scsi_8btou64(response->vendor_specific)); 484 } 485 486 /* 487 * Compose a SMP REPORT GENERAL request and put it into a CCB. This is 488 * current as of SPL Revision 7. 489 */ 490 void 491 smp_report_general(struct ccb_smpio *smpio, uint32_t retries, 492 void (*cbfcnp)(struct cam_periph *, union ccb *), 493 struct smp_report_general_request *request, int request_len, 494 uint8_t *response, int response_len, int long_response, 495 uint32_t timeout) 496 { 497 cam_fill_smpio(smpio, 498 retries, 499 cbfcnp, 500 /*flags*/CAM_DIR_BOTH, 501 (uint8_t *)request, 502 request_len - SMP_CRC_LEN, 503 response, 504 response_len, 505 timeout); 506 507 bzero(request, sizeof(*request)); 508 509 request->frame_type = SMP_FRAME_TYPE_REQUEST; 510 request->function = SMP_FUNC_REPORT_GENERAL; 511 request->response_len = long_response ? SMP_RG_RESPONSE_LEN : 0; 512 request->request_len = 0; 513 } 514 515 /* 516 * Compose a SMP DISCOVER request and put it into a CCB. This is current 517 * as of SPL Revision 7. 518 */ 519 void 520 smp_discover(struct ccb_smpio *smpio, uint32_t retries, 521 void (*cbfcnp)(struct cam_periph *, union ccb *), 522 struct smp_discover_request *request, int request_len, 523 uint8_t *response, int response_len, int long_response, 524 int ignore_zone_group, int phy, uint32_t timeout) 525 { 526 cam_fill_smpio(smpio, 527 retries, 528 cbfcnp, 529 /*flags*/CAM_DIR_BOTH, 530 (uint8_t *)request, 531 request_len - SMP_CRC_LEN, 532 response, 533 response_len, 534 timeout); 535 536 bzero(request, sizeof(*request)); 537 request->frame_type = SMP_FRAME_TYPE_REQUEST; 538 request->function = SMP_FUNC_DISCOVER; 539 request->response_len = long_response ? SMP_DIS_RESPONSE_LEN : 0; 540 request->request_len = long_response ? SMP_DIS_REQUEST_LEN : 0; 541 if (ignore_zone_group != 0) 542 request->ignore_zone_group |= SMP_DIS_IGNORE_ZONE_GROUP; 543 request->phy = phy; 544 } 545 546 /* 547 * Compose a SMP REPORT MANUFACTURER INFORMATION request and put it into a 548 * CCB. This is current as of SPL Revision 7. 549 */ 550 void 551 smp_report_manuf_info(struct ccb_smpio *smpio, uint32_t retries, 552 void (*cbfcnp)(struct cam_periph *, union ccb *), 553 struct smp_report_manuf_info_request *request, 554 int request_len, uint8_t *response, int response_len, 555 int long_response, uint32_t timeout) 556 { 557 cam_fill_smpio(smpio, 558 retries, 559 cbfcnp, 560 /*flags*/CAM_DIR_BOTH, 561 (uint8_t *)request, 562 request_len - SMP_CRC_LEN, 563 response, 564 response_len, 565 timeout); 566 567 bzero(request, sizeof(*request)); 568 569 request->frame_type = SMP_FRAME_TYPE_REQUEST; 570 request->function = SMP_FUNC_REPORT_MANUF_INFO; 571 request->response_len = long_response ? SMP_RMI_RESPONSE_LEN : 0; 572 request->request_len = long_response ? SMP_RMI_REQUEST_LEN : 0; 573 } 574 575 /* 576 * Compose a SMP PHY CONTROL request and put it into a CCB. This is 577 * current as of SPL Revision 7. 578 */ 579 void 580 smp_phy_control(struct ccb_smpio *smpio, uint32_t retries, 581 void (*cbfcnp)(struct cam_periph *, union ccb *), 582 struct smp_phy_control_request *request, int request_len, 583 uint8_t *response, int response_len, int long_response, 584 uint32_t expected_exp_change_count, int phy, int phy_op, 585 int update_pp_timeout_val, uint64_t attached_device_name, 586 int prog_min_prl, int prog_max_prl, int slumber_partial, 587 int pp_timeout_value, uint32_t timeout) 588 { 589 cam_fill_smpio(smpio, 590 retries, 591 cbfcnp, 592 /*flags*/CAM_DIR_BOTH, 593 (uint8_t *)request, 594 request_len - SMP_CRC_LEN, 595 response, 596 response_len, 597 timeout); 598 599 bzero(request, sizeof(*request)); 600 601 request->frame_type = SMP_FRAME_TYPE_REQUEST; 602 request->function = SMP_FUNC_PHY_CONTROL; 603 request->response_len = long_response ? SMP_PC_RESPONSE_LEN : 0; 604 request->request_len = long_response ? SMP_PC_REQUEST_LEN : 0; 605 scsi_ulto2b(expected_exp_change_count, request->expected_exp_chg_cnt); 606 request->phy = phy; 607 request->phy_operation = phy_op; 608 609 if (update_pp_timeout_val != 0) 610 request->update_pp_timeout |= SMP_PC_UPDATE_PP_TIMEOUT; 611 612 scsi_u64to8b(attached_device_name, request->attached_device_name); 613 request->prog_min_phys_link_rate = (prog_min_prl << 614 SMP_PC_PROG_MIN_PL_RATE_SHIFT) & SMP_PC_PROG_MIN_PL_RATE_MASK; 615 request->prog_max_phys_link_rate = (prog_max_prl << 616 SMP_PC_PROG_MAX_PL_RATE_SHIFT) & SMP_PC_PROG_MAX_PL_RATE_MASK; 617 request->config_bits0 = slumber_partial; 618 request->pp_timeout_value = pp_timeout_value; 619 } 620 621