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