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