smp_all.c revision 302408
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: stable/11/sys/cam/scsi/smp_all.c 298431 2016-04-21 19:40:10Z pfg $");
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
64static char *smp_yesno(int val);
65
66static char *
67smp_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
79struct smp_error_table_entry {
80	uint8_t	function_result;
81	const char *desc;
82};
83
84/* List current as of SPL Revision 7 */
85static 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
116const char *
117smp_error_desc(int function_result)
118{
119	int i;
120
121	for (i = 0; i < nitems(smp_error_table); i++){
122		if (function_result == smp_error_table[i].function_result)
123			return (smp_error_table[i].desc);
124	}
125	return ("Reserved Function Result");
126}
127
128/* List current as of SPL Revision 7 */
129struct smp_cmd_table_entry {
130	uint8_t	cmd_num;
131	const char *desc;
132} smp_cmd_table[] = {
133	{SMP_FUNC_REPORT_GENERAL, "REPORT GENERAL"},
134	{SMP_FUNC_REPORT_MANUF_INFO, "REPORT MANUFACTURER INFORMATION"},
135	{SMP_FUNC_REPORT_SC_STATUS, "REPORT SELF-CONFIGURATION STATUS"},
136	{SMP_FUNC_REPORT_ZONE_PERM_TBL, "REPORT ZONE PERMISSION TABLE"},
137	{SMP_FUNC_REPORT_BROADCAST, "REPORT BROADCAST"},
138	{SMP_FUNC_DISCOVER, "DISCOVER"},
139	{SMP_FUNC_REPORT_PHY_ERR_LOG, "REPORT PHY ERROR LOG"},
140	{SMP_FUNC_REPORT_PHY_SATA, "REPORT PHY SATA"},
141	{SMP_FUNC_REPORT_ROUTE_INFO, "REPORT ROUTE INFORMATION"},
142	{SMP_FUNC_REPORT_PHY_EVENT, "REPORT PHY EVENT"},
143	{SMP_FUNC_DISCOVER_LIST, "DISCOVER LIST"},
144	{SMP_FUNC_REPORT_PHY_EVENT_LIST, "REPORT PHY EVENT LIST"},
145	{SMP_FUNC_REPORT_EXP_RTL, "REPORT EXPANDER ROUTE TABLE LIST"},
146	{SMP_FUNC_CONFIG_GENERAL, "CONFIGURE GENERAL"},
147	{SMP_FUNC_ENABLE_DISABLE_ZONING, "ENABLE DISABLE ZONING"},
148	{SMP_FUNC_ZONED_BROADCAST, "ZONED BROADCAST"},
149	{SMP_FUNC_ZONE_LOCK, "ZONE LOCK"},
150	{SMP_FUNC_ZONE_ACTIVATE, "ZONE ACTIVATE"},
151	{SMP_FUNC_ZONE_UNLOCK, "ZONE UNLOCK"},
152	{SMP_FUNC_CONFIG_ZM_PWD, "CONFIGURE ZONE MANAGER PASSWORD"},
153	{SMP_FUNC_CONFIG_ZONE_PHY_INFO, "CONFIGURE ZONE PHY INFORMATION"},
154	{SMP_FUNC_CONFIG_ZONE_PERM_TBL, "CONFIGURE ZONE PERMISSION TABLE"},
155	{SMP_FUNC_CONFIG_ROUTE_INFO, "CONFIGURE ROUTE INFORMATION"},
156	{SMP_FUNC_PHY_CONTROL, "PHY CONTROL"},
157	{SMP_FUNC_PHY_TEST_FUNC, "PHY TEST FUNCTION"},
158	{SMP_FUNC_CONFIG_PHY_EVENT, "CONFIGURE PHY EVENT"}
159};
160
161const char *
162smp_command_desc(uint8_t cmd_num)
163{
164	int i;
165
166	for (i = 0; i < nitems(smp_cmd_table) &&
167	     smp_cmd_table[i].cmd_num <= cmd_num; i++) {
168		if (cmd_num == smp_cmd_table[i].cmd_num)
169			return (smp_cmd_table[i].desc);
170	}
171
172	/*
173	 * 0x40 to 0x7f and 0xc0 to 0xff are the vendor specific SMP
174	 * command ranges.
175	 */
176	if (((cmd_num >= 0x40) && (cmd_num <= 0x7f))
177	 || (cmd_num >= 0xc0)) {
178		return ("Vendor Specific SMP Command");
179	} else {
180		return ("Unknown SMP Command");
181	}
182}
183
184/*
185 * Decode a SMP request buffer into a string of hexadecimal numbers.
186 *
187 * smp_request:    SMP request
188 * request_len:    length of the SMP request buffer, may be reduced if the
189 *                 caller only wants part of the buffer printed
190 * sb:             sbuf(9) buffer
191 * line_prefix:    prefix for new lines, or an empty string ("")
192 * first_line_len: length left on first line
193 * line_len:       total length of subsequent lines, 0 for no additional lines
194 *                 if there are no additional lines, first line will get ...
195 *                 at the end if there is additional data
196 */
197void
198smp_command_decode(uint8_t *smp_request, int request_len, struct sbuf *sb,
199		   char *line_prefix, int first_line_len, int line_len)
200{
201	int i, cur_len;
202
203	for (i = 0, cur_len = first_line_len; i < request_len; i++) {
204		/*
205		 * Each byte takes 3 characters.  As soon as we go less
206		 * than 6 (meaning we have at least 3 and at most 5
207		 * characters left), check to see whether the subsequent
208		 * line length (line_len) is long enough to bother with.
209		 * If the user set it to 0, or some other length that isn't
210		 * enough to hold at least the prefix and one byte, put ...
211		 * on the first line to indicate that there is more data
212		 * and bail out.
213		 */
214		if ((cur_len < 6)
215		 && (line_len < (strlen(line_prefix) + 3))) {
216			sbuf_printf(sb, "...");
217			return;
218		}
219		if (cur_len < 3) {
220			sbuf_printf(sb, "\n%s", line_prefix);
221			cur_len = line_len - strlen(line_prefix);
222		}
223		sbuf_printf(sb, "%02x ", smp_request[i]);
224		cur_len = cur_len - 3;
225	}
226}
227
228void
229smp_command_sbuf(struct ccb_smpio *smpio, struct sbuf *sb,
230		 char *line_prefix, int first_line_len, int line_len)
231{
232	sbuf_printf(sb, "%s. ", smp_command_desc(smpio->smp_request[1]));
233
234	/*
235	 * Acccount for the command description and the period and space
236	 * after the command description.
237	 */
238	first_line_len -= strlen(smp_command_desc(smpio->smp_request[1])) + 2;
239
240	smp_command_decode(smpio->smp_request, smpio->smp_request_len, sb,
241			   line_prefix, first_line_len, line_len);
242}
243
244/*
245 * Print SMP error output.  For userland commands, we need the cam_device
246 * structure so we can get the path information from the CCB.
247 */
248#ifdef _KERNEL
249void
250smp_error_sbuf(struct ccb_smpio *smpio, struct sbuf *sb)
251#else /* !_KERNEL*/
252void
253smp_error_sbuf(struct cam_device *device, struct ccb_smpio *smpio,
254	       struct sbuf *sb)
255#endif /* _KERNEL/!_KERNEL */
256{
257	char path_str[64];
258
259#ifdef _KERNEL
260	xpt_path_string(smpio->ccb_h.path, path_str, sizeof(path_str));
261#else
262	cam_path_string(device, path_str, sizeof(path_str));
263#endif
264	smp_command_sbuf(smpio, sb, path_str, 80 - strlen(path_str), 80);
265	sbuf_printf(sb, "\n");
266
267	sbuf_cat(sb, path_str);
268	sbuf_printf(sb, "SMP Error: %s (0x%x)\n",
269		    smp_error_desc(smpio->smp_response[2]),
270		    smpio->smp_response[2]);
271}
272
273/*
274 * Decode the SMP REPORT GENERAL response.  The format is current as of SPL
275 * Revision 7, but the parsing should be backward compatible for older
276 * versions of the spec.
277 */
278void
279smp_report_general_sbuf(struct smp_report_general_response *response,
280			int response_len, struct sbuf *sb)
281{
282	sbuf_printf(sb, "Report General\n");
283	sbuf_printf(sb, "Response Length: %d words (%d bytes)\n",
284		    response->response_len,
285		    response->response_len * SMP_WORD_LEN);
286	sbuf_printf(sb, "Expander Change Count: %d\n",
287		    scsi_2btoul(response->expander_change_count));
288	sbuf_printf(sb, "Expander Route Indexes: %d\n",
289		    scsi_2btoul(response->expander_route_indexes));
290	sbuf_printf(sb, "Long Response: %s\n",
291		    smp_yesno(response->long_response &
292			      SMP_RG_LONG_RESPONSE));
293	sbuf_printf(sb, "Number of Phys: %d\n", response->num_phys);
294	sbuf_printf(sb, "Table to Table Supported: %s\n",
295		    smp_yesno(response->config_bits0 &
296		    SMP_RG_TABLE_TO_TABLE_SUP));
297	sbuf_printf(sb, "Zone Configuring: %s\n",
298		    smp_yesno(response->config_bits0 &
299		    SMP_RG_ZONE_CONFIGURING));
300	sbuf_printf(sb, "Self Configuring: %s\n",
301		    smp_yesno(response->config_bits0 &
302		    SMP_RG_SELF_CONFIGURING));
303	sbuf_printf(sb, "STP Continue AWT: %s\n",
304		    smp_yesno(response->config_bits0 &
305		    SMP_RG_STP_CONTINUE_AWT));
306	sbuf_printf(sb, "Open Reject Retry Supported: %s\n",
307		    smp_yesno(response->config_bits0 &
308		    SMP_RG_OPEN_REJECT_RETRY_SUP));
309	sbuf_printf(sb, "Configures Others: %s\n",
310		    smp_yesno(response->config_bits0 &
311		    SMP_RG_CONFIGURES_OTHERS));
312	sbuf_printf(sb, "Configuring: %s\n",
313		    smp_yesno(response->config_bits0 &
314		    SMP_RG_CONFIGURING));
315	sbuf_printf(sb, "Externally Configurable Route Table: %s\n",
316		    smp_yesno(response->config_bits0 &
317		    SMP_RG_CONFIGURING));
318	sbuf_printf(sb, "Enclosure Logical Identifier: 0x%016jx\n",
319		    (uintmax_t)scsi_8btou64(response->encl_logical_id));
320
321	/*
322	 * If the response->response_len is 0, then we don't have the
323	 * extended information.  Also, if the user didn't allocate enough
324	 * space for the full request, don't try to parse it.
325	 */
326	if ((response->response_len == 0)
327	 || (response_len < (sizeof(struct smp_report_general_response) -
328	     sizeof(response->crc))))
329		return;
330
331	sbuf_printf(sb, "STP Bus Inactivity Time Limit: %d\n",
332		    scsi_2btoul(response->stp_bus_inact_time_limit));
333	sbuf_printf(sb, "STP Maximum Connect Time Limit: %d\n",
334		    scsi_2btoul(response->stp_max_conn_time_limit));
335	sbuf_printf(sb, "STP SMP I_T Nexus Loss Time: %d\n",
336		    scsi_2btoul(response->stp_smp_it_nexus_loss_time));
337
338	sbuf_printf(sb, "Number of Zone Groups: %d\n",
339		    (response->config_bits1 & SMP_RG_NUM_ZONE_GROUPS_MASK) >>
340		    SMP_RG_NUM_ZONE_GROUPS_SHIFT);
341	sbuf_printf(sb, "Zone Locked: %s\n",
342		    smp_yesno(response->config_bits1 & SMP_RG_ZONE_LOCKED));
343	sbuf_printf(sb, "Physical Presence Supported: %s\n",
344		    smp_yesno(response->config_bits1 & SMP_RG_PP_SUPPORTED));
345	sbuf_printf(sb, "Physical Presence Asserted: %s\n",
346		    smp_yesno(response->config_bits1 & SMP_RG_PP_ASSERTED));
347	sbuf_printf(sb, "Zoning Supported: %s\n",
348		    smp_yesno(response->config_bits1 &
349			      SMP_RG_ZONING_SUPPORTED));
350	sbuf_printf(sb, "Zoning Enabled: %s\n",
351		    smp_yesno(response->config_bits1 & SMP_RG_ZONING_ENABLED));
352
353	sbuf_printf(sb, "Saving: %s\n",
354		    smp_yesno(response->config_bits2 & SMP_RG_SAVING));
355	sbuf_printf(sb, "Saving Zone Manager Password Supported: %s\n",
356		    smp_yesno(response->config_bits2 &
357			      SMP_RG_SAVING_ZM_PWD_SUP));
358	sbuf_printf(sb, "Saving Zone Phy Information Supported: %s\n",
359		    smp_yesno(response->config_bits2 &
360			      SMP_RG_SAVING_PHY_INFO_SUP));
361	sbuf_printf(sb, "Saving Zone Permission Table Supported: %s\n",
362		    smp_yesno(response->config_bits2 &
363			      SMP_RG_SAVING_ZPERM_TAB_SUP));
364	sbuf_printf(sb, "Saving Zoning Enabled Supported: %s\n",
365		    smp_yesno(response->config_bits2 &
366			      SMP_RG_SAVING_ZENABLED_SUP));
367
368	sbuf_printf(sb, "Maximum Number of Routed SAS Addresses: %d\n",
369		    scsi_2btoul(response->max_num_routed_addrs));
370
371	sbuf_printf(sb, "Active Zone Manager SAS Address: 0x%016jx\n",
372		    scsi_8btou64(response->active_zm_address));
373
374	sbuf_printf(sb, "Zone Inactivity Time Limit: %d\n",
375		    scsi_2btoul(response->zone_lock_inact_time_limit));
376
377	sbuf_printf(sb, "First Enclosure Connector Element Index: %d\n",
378		    response->first_encl_conn_el_index);
379
380	sbuf_printf(sb, "Number of Enclosure Connector Element Indexes: %d\n",
381		    response->num_encl_conn_el_indexes);
382
383	sbuf_printf(sb, "Reduced Functionality: %s\n",
384		    smp_yesno(response->reduced_functionality &
385			      SMP_RG_REDUCED_FUNCTIONALITY));
386
387	sbuf_printf(sb, "Time to Reduced Functionality: %d\n",
388		    response->time_to_reduced_func);
389	sbuf_printf(sb, "Initial Time to Reduced Functionality: %d\n",
390		    response->initial_time_to_reduced_func);
391	sbuf_printf(sb, "Maximum Reduced Functionality Time: %d\n",
392		    response->max_reduced_func_time);
393
394	sbuf_printf(sb, "Last Self-Configuration Status Descriptor Index: %d\n",
395		    scsi_2btoul(response->last_sc_stat_desc_index));
396
397	sbuf_printf(sb, "Maximum Number of Storated Self-Configuration "
398		    "Status Descriptors: %d\n",
399		    scsi_2btoul(response->max_sc_stat_descs));
400
401	sbuf_printf(sb, "Last Phy Event List Descriptor Index: %d\n",
402		    scsi_2btoul(response->last_phy_evl_desc_index));
403
404	sbuf_printf(sb, "Maximum Number of Stored Phy Event List "
405		    "Descriptors: %d\n",
406		    scsi_2btoul(response->max_stored_pel_descs));
407
408	sbuf_printf(sb, "STP Reject to Open Limit: %d\n",
409		    scsi_2btoul(response->stp_reject_to_open_limit));
410}
411
412/*
413 * Decode the SMP REPORT MANUFACTURER INFORMATION response.  The format is
414 * current as of SPL Revision 7, but the parsing should be backward
415 * compatible for older versions of the spec.
416 */
417void
418smp_report_manuf_info_sbuf(struct smp_report_manuf_info_response *response,
419			   int response_len, struct sbuf *sb)
420{
421	char vendor[16], product[48], revision[16];
422	char comp_vendor[16];
423
424	sbuf_printf(sb, "Report Manufacturer Information\n");
425	sbuf_printf(sb, "Expander Change count: %d\n",
426		    scsi_2btoul(response->expander_change_count));
427	sbuf_printf(sb, "SAS 1.1 Format: %s\n",
428		    smp_yesno(response->sas_11_format & SMP_RMI_SAS11_FORMAT));
429	cam_strvis(vendor, response->vendor, sizeof(response->vendor),
430		   sizeof(vendor));
431	cam_strvis(product, response->product, sizeof(response->product),
432		   sizeof(product));
433	cam_strvis(revision, response->revision, sizeof(response->revision),
434		   sizeof(revision));
435	sbuf_printf(sb, "<%s %s %s>\n", vendor, product, revision);
436
437	if ((response->sas_11_format & SMP_RMI_SAS11_FORMAT) == 0) {
438		uint8_t *curbyte;
439		int line_start, line_cursor;
440
441		sbuf_printf(sb, "Vendor Specific Data:\n");
442
443		/*
444		 * Print out the bytes roughly in the style of hd(1), but
445		 * without the extra ASCII decoding.  Hexadecimal line
446		 * numbers on the left, and 16 bytes per line, with an
447		 * extra space after the first 8 bytes.
448		 *
449		 * It would be nice if this sort of thing were available
450		 * in a library routine.
451		 */
452		for (curbyte = (uint8_t *)&response->comp_vendor, line_start= 1,
453		     line_cursor = 0; curbyte < (uint8_t *)&response->crc;
454		     curbyte++, line_cursor++) {
455			if (line_start != 0) {
456				sbuf_printf(sb, "%08lx  ",
457					    (unsigned long)(curbyte -
458					    (uint8_t *)response));
459				line_start = 0;
460				line_cursor = 0;
461			}
462			sbuf_printf(sb, "%02x", *curbyte);
463
464			if (line_cursor == 15) {
465				sbuf_printf(sb, "\n");
466				line_start = 1;
467			} else
468				sbuf_printf(sb, " %s", (line_cursor == 7) ?
469					    " " : "");
470		}
471		if (line_cursor != 16)
472			sbuf_printf(sb, "\n");
473		return;
474	}
475
476	cam_strvis(comp_vendor, response->comp_vendor,
477		   sizeof(response->comp_vendor), sizeof(comp_vendor));
478	sbuf_printf(sb, "Component Vendor: %s\n", comp_vendor);
479	sbuf_printf(sb, "Component ID: %#x\n", scsi_2btoul(response->comp_id));
480	sbuf_printf(sb, "Component Revision: %#x\n", response->comp_revision);
481	sbuf_printf(sb, "Vendor Specific: 0x%016jx\n",
482		    (uintmax_t)scsi_8btou64(response->vendor_specific));
483}
484
485/*
486 * Compose a SMP REPORT GENERAL request and put it into a CCB.  This is
487 * current as of SPL Revision 7.
488 */
489void
490smp_report_general(struct ccb_smpio *smpio, uint32_t retries,
491		   void (*cbfcnp)(struct cam_periph *, union ccb *),
492		   struct smp_report_general_request *request, int request_len,
493		   uint8_t *response, int response_len, int long_response,
494		   uint32_t timeout)
495{
496	cam_fill_smpio(smpio,
497		       retries,
498		       cbfcnp,
499		       /*flags*/CAM_DIR_BOTH,
500		       (uint8_t *)request,
501		       request_len - SMP_CRC_LEN,
502		       response,
503		       response_len,
504		       timeout);
505
506	bzero(request, sizeof(*request));
507
508	request->frame_type = SMP_FRAME_TYPE_REQUEST;
509	request->function = SMP_FUNC_REPORT_GENERAL;
510	request->response_len = long_response ? SMP_RG_RESPONSE_LEN : 0;
511	request->request_len = 0;
512}
513
514/*
515 * Compose a SMP DISCOVER request and put it into a CCB.  This is current
516 * as of SPL Revision 7.
517 */
518void
519smp_discover(struct ccb_smpio *smpio, uint32_t retries,
520	     void (*cbfcnp)(struct cam_periph *, union ccb *),
521	     struct smp_discover_request *request, int request_len,
522	     uint8_t *response, int response_len, int long_response,
523	     int ignore_zone_group, int phy, uint32_t timeout)
524{
525	cam_fill_smpio(smpio,
526		       retries,
527		       cbfcnp,
528		       /*flags*/CAM_DIR_BOTH,
529		       (uint8_t *)request,
530		       request_len - SMP_CRC_LEN,
531		       response,
532		       response_len,
533		       timeout);
534
535	bzero(request, sizeof(*request));
536	request->frame_type = SMP_FRAME_TYPE_REQUEST;
537	request->function = SMP_FUNC_DISCOVER;
538	request->response_len = long_response ? SMP_DIS_RESPONSE_LEN : 0;
539	request->request_len = long_response ? SMP_DIS_REQUEST_LEN : 0;
540	if (ignore_zone_group != 0)
541		request->ignore_zone_group |= SMP_DIS_IGNORE_ZONE_GROUP;
542	request->phy = phy;
543}
544
545/*
546 * Compose a SMP REPORT MANUFACTURER INFORMATION request and put it into a
547 * CCB.  This is current as of SPL Revision 7.
548 */
549void
550smp_report_manuf_info(struct ccb_smpio *smpio, uint32_t retries,
551		      void (*cbfcnp)(struct cam_periph *, union ccb *),
552		      struct smp_report_manuf_info_request *request,
553		      int request_len, uint8_t *response, int response_len,
554		      int long_response, uint32_t timeout)
555{
556	cam_fill_smpio(smpio,
557		       retries,
558		       cbfcnp,
559		       /*flags*/CAM_DIR_BOTH,
560		       (uint8_t *)request,
561		       request_len - SMP_CRC_LEN,
562		       response,
563		       response_len,
564		       timeout);
565
566	bzero(request, sizeof(*request));
567
568	request->frame_type = SMP_FRAME_TYPE_REQUEST;
569	request->function = SMP_FUNC_REPORT_MANUF_INFO;
570	request->response_len = long_response ? SMP_RMI_RESPONSE_LEN : 0;
571	request->request_len = long_response ? SMP_RMI_REQUEST_LEN : 0;
572}
573
574/*
575 * Compose a SMP PHY CONTROL request and put it into a CCB.  This is
576 * current as of SPL Revision 7.
577 */
578void
579smp_phy_control(struct ccb_smpio *smpio, uint32_t retries,
580		void (*cbfcnp)(struct cam_periph *, union ccb *),
581		struct smp_phy_control_request *request, int request_len,
582		uint8_t *response, int response_len, int long_response,
583		uint32_t expected_exp_change_count, int phy, int phy_op,
584		int update_pp_timeout_val, uint64_t attached_device_name,
585		int prog_min_prl, int prog_max_prl, int slumber_partial,
586		int pp_timeout_value, uint32_t timeout)
587{
588	cam_fill_smpio(smpio,
589		       retries,
590		       cbfcnp,
591		       /*flags*/CAM_DIR_BOTH,
592		       (uint8_t *)request,
593		       request_len - SMP_CRC_LEN,
594		       response,
595		       response_len,
596		       timeout);
597
598	bzero(request, sizeof(*request));
599
600	request->frame_type = SMP_FRAME_TYPE_REQUEST;
601	request->function = SMP_FUNC_PHY_CONTROL;
602	request->response_len = long_response ? SMP_PC_RESPONSE_LEN : 0;
603	request->request_len = long_response ? SMP_PC_REQUEST_LEN : 0;
604	scsi_ulto2b(expected_exp_change_count, request->expected_exp_chg_cnt);
605	request->phy = phy;
606	request->phy_operation = phy_op;
607
608	if (update_pp_timeout_val != 0)
609		request->update_pp_timeout |= SMP_PC_UPDATE_PP_TIMEOUT;
610
611	scsi_u64to8b(attached_device_name, request->attached_device_name);
612	request->prog_min_phys_link_rate = (prog_min_prl <<
613		SMP_PC_PROG_MIN_PL_RATE_SHIFT) & SMP_PC_PROG_MIN_PL_RATE_MASK;
614	request->prog_max_phys_link_rate = (prog_max_prl <<
615		SMP_PC_PROG_MAX_PL_RATE_SHIFT) & SMP_PC_PROG_MAX_PL_RATE_MASK;
616	request->config_bits0 = slumber_partial;
617	request->pp_timeout_value = pp_timeout_value;
618}
619
620