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