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