Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/cam/scsi/smp_all.c
39482 views
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
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
619