xref: /titanic_52/usr/src/lib/scsi/plugins/smp/sas2/common/sas2_functions.c (revision d0698e0d179f97729cacdbc2f13446a6b0a3f22a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/scsi/generic/commands.h>
28 #include <sys/scsi/impl/commands.h>
29 #include <sys/scsi/generic/smp_frames.h>
30 
31 #include <scsi/libsmp.h>
32 #include <scsi/libsmp_plugin.h>
33 #include "sas2.h"
34 
35 /*ARGSUSED*/
36 static size_t
37 sas2_rq_len(size_t user, smp_target_t *tp)
38 {
39 	if (user != 0) {
40 		(void) smp_set_errno(ESMP_RANGE);
41 		return (0);
42 	}
43 
44 	return (SMP_REQ_MINLEN);
45 }
46 
47 /*ARGSUSED*/
48 static off_t
49 sas2_rq_dataoff(smp_action_t *ap, smp_target_t *tp)
50 {
51 	size_t len;
52 
53 	smp_action_get_request_frame(ap, NULL, &len);
54 
55 	if (len > SMP_REQ_MINLEN)
56 		return (offsetof(smp_request_frame_t, srf_data[0]));
57 
58 	return (-1);
59 }
60 
61 static void
62 sas2_rq_setframe(smp_action_t *ap, smp_target_t *tp)
63 {
64 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
65 	smp_request_frame_t *fp;
66 	uint_t cap;
67 	uint16_t change_count;
68 	uint16_t *rqcc;
69 	size_t rqlen, rslen;
70 
71 	smp_action_get_request_frame(ap, (void *)&fp, &rqlen);
72 	smp_action_get_response_frame(ap, NULL, &rslen);
73 	cap = smp_target_getcap(tp);
74 
75 	fp->srf_frame_type = SMP_FRAME_TYPE_REQUEST;
76 	fp->srf_function = dp->sfd_function;
77 
78 	if (cap & SMP_TARGET_C_LONG_RESP) {
79 		fp->srf_allocated_response_len = (rslen - SMP_RESP_MINLEN) / 4;
80 		fp->srf_request_len = (rqlen - SMP_REQ_MINLEN) / 4;
81 	} else {
82 		fp->srf_allocated_response_len = 0;
83 		fp->srf_request_len = 0;
84 	}
85 
86 	/*
87 	 * If this command requires that the expected expander change count
88 	 * be set (as many do), we will attempt to set it based on the
89 	 * most recently executed command.  However, if the user has set it
90 	 * already, we will not overwrite that setting.  It is the consumer's
91 	 * responsibility to keep track of expander changes each time it
92 	 * receives a new change count in a response.
93 	 */
94 	if (dp->sfd_flags & SMP_FD_F_NEEDS_CHANGE_COUNT) {
95 		ASSERT(rqlen >= SMP_REQ_MINLEN + sizeof (uint16_t));
96 		/* LINTED - alignment */
97 		rqcc = (uint16_t *)(&fp->srf_data[0]);
98 		if (SCSI_READ16(rqcc) == 0) {
99 			change_count = smp_target_get_change_count(tp);
100 			SCSI_WRITE16(rqcc, change_count);
101 		}
102 	}
103 }
104 
105 /*ARGSUSED*/
106 static size_t
107 sas2_rs_datalen(smp_action_t *ap, smp_target_t *tp)
108 {
109 	smp_response_frame_t *fp;
110 	size_t len;
111 
112 	smp_action_get_response_frame(ap, (void **)&fp, &len);
113 
114 	if (len >= SMP_RESP_MINLEN)
115 		len -= SMP_RESP_MINLEN;
116 	else
117 		return (0);
118 
119 	len &= ~3;
120 
121 	if (fp->srf_response_len == 0)
122 		return (0);
123 
124 	return (MIN(len, 4 * (fp->srf_response_len)));
125 }
126 
127 /*ARGSUSED*/
128 static off_t
129 sas2_rs_dataoff(smp_action_t *ap, smp_target_t *tp)
130 {
131 	size_t len;
132 
133 	smp_action_get_response_frame(ap, NULL, &len);
134 
135 	if (len > SMP_RESP_MINLEN)
136 		return (offsetof(smp_request_frame_t, srf_data[0]));
137 
138 	return (-1);
139 }
140 
141 static void
142 sas2_rs_getparams(smp_action_t *ap, smp_target_t *tp)
143 {
144 	const smp_function_def_t *dp;
145 	smp_response_frame_t *fp;
146 	size_t len;
147 	uint16_t change_count;
148 
149 	dp = smp_action_get_function_def(ap);
150 
151 	smp_action_get_response_frame(ap, (void **)&fp, &len);
152 
153 	smp_action_set_result(ap, fp->srf_result);
154 
155 	if (!(dp->sfd_flags & SMP_FD_F_PROVIDES_CHANGE_COUNT))
156 		return;
157 
158 	if (len <= SMP_RESP_MINLEN + sizeof (uint16_t))
159 		return;
160 
161 	change_count = SCSI_READ16(&fp->srf_data[0]);
162 	smp_target_set_change_count(tp, change_count);
163 }
164 
165 /*ARGSUSED*/
166 static size_t
167 sas2_report_general_rs_datalen(smp_action_t *ap, smp_target_t *tp)
168 {
169 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
170 	smp_response_frame_t *fp;
171 	size_t len;
172 
173 	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_GENERAL);
174 	smp_action_get_response_frame(ap, (void **)&fp, &len);
175 
176 	if (len >= SMP_RESP_MINLEN)
177 		len -= SMP_RESP_MINLEN;
178 	else
179 		return (0);
180 
181 	len &= ~3;
182 
183 	if (fp->srf_response_len == 0)
184 		return (MIN(len, 24));
185 
186 	return (MIN(len, 4 * (fp->srf_response_len)));
187 }
188 
189 /*ARGSUSED*/
190 static size_t
191 sas2_report_manufacturer_info_rs_datalen(smp_action_t *ap, smp_target_t *tp)
192 {
193 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
194 	smp_response_frame_t *fp;
195 	size_t len;
196 
197 	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_MANUFACTURER_INFO);
198 	smp_action_get_response_frame(ap, (void **)&fp, &len);
199 
200 	if (len >= SMP_RESP_MINLEN)
201 		len -= SMP_RESP_MINLEN;
202 	else
203 		return (0);
204 
205 	len &= ~3;
206 
207 	if (fp->srf_response_len == 0)
208 		return (MIN(len, 56));
209 
210 	return (MIN(len, 4 * (fp->srf_response_len)));
211 }
212 
213 /*ARGSUSED*/
214 static size_t
215 sas2_report_self_config_status_rq_len(size_t user, smp_target_t *tp)
216 {
217 	if (user != 0) {
218 		(void) smp_set_errno(ESMP_RANGE);
219 		return (0);
220 	}
221 
222 	return (SMP_REQ_MINLEN + sizeof (smp_report_self_config_status_req_t));
223 }
224 
225 /*ARGSUSED*/
226 static size_t
227 sas2_report_zone_perm_table_rq_len(size_t user, smp_target_t *tp)
228 {
229 	if (user != 0) {
230 		(void) smp_set_errno(ESMP_RANGE);
231 		return (0);
232 	}
233 
234 	return (SMP_REQ_MINLEN + sizeof (smp_report_zone_perm_table_req_t));
235 }
236 
237 /*ARGSUSED*/
238 static size_t
239 sas2_report_zone_mgr_password_rq_len(size_t user, smp_target_t *tp)
240 {
241 	if (user != 0) {
242 		(void) smp_set_errno(ESMP_RANGE);
243 		return (0);
244 	}
245 
246 	return (SMP_REQ_MINLEN + sizeof (smp_report_zone_perm_table_req_t));
247 }
248 
249 /*ARGSUSED*/
250 static size_t
251 sas2_report_broadcast_rq_len(size_t user, smp_target_t *tp)
252 {
253 	if (user != 0) {
254 		(void) smp_set_errno(ESMP_RANGE);
255 		return (0);
256 	}
257 
258 	return (SMP_REQ_MINLEN + sizeof (smp_report_broadcast_req_t));
259 }
260 
261 /*ARGSUSED*/
262 static size_t
263 sas2_discover_rq_len(size_t user, smp_target_t *tp)
264 {
265 	if (user != 0) {
266 		(void) smp_set_errno(ESMP_RANGE);
267 		return (0);
268 	}
269 
270 	return (SMP_REQ_MINLEN + sizeof (smp_discover_req_t));
271 }
272 
273 /*ARGSUSED*/
274 static size_t
275 sas2_discover_rs_datalen(smp_action_t *ap, smp_target_t *tp)
276 {
277 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
278 	smp_response_frame_t *fp;
279 	size_t len;
280 
281 	ASSERT(dp->sfd_function == SMP_FUNC_DISCOVER);
282 	smp_action_get_response_frame(ap, (void **)&fp, &len);
283 
284 	if (len >= SMP_RESP_MINLEN)
285 		len -= SMP_RESP_MINLEN;
286 	else
287 		return (0);
288 
289 	len &= ~3;
290 
291 	if (fp->srf_response_len == 0)
292 		return (MIN(len, 48));
293 
294 	return (MIN(len, 4 * (fp->srf_response_len)));
295 }
296 
297 /*ARGSUSED*/
298 static size_t
299 sas2_report_phy_error_log_rq_len(size_t user, smp_target_t *tp)
300 {
301 	if (user != 0) {
302 		(void) smp_set_errno(ESMP_RANGE);
303 		return (0);
304 	}
305 
306 	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_error_log_req_t));
307 }
308 
309 /*ARGSUSED*/
310 static size_t
311 sas2_report_phy_error_log_rs_datalen(smp_action_t *ap, smp_target_t *tp)
312 {
313 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
314 	smp_response_frame_t *fp;
315 	size_t len;
316 
317 	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_PHY_ERROR_LOG);
318 	smp_action_get_response_frame(ap, (void **)&fp, &len);
319 
320 	if (len >= SMP_RESP_MINLEN)
321 		len -= SMP_RESP_MINLEN;
322 	else
323 		return (0);
324 
325 	len &= ~3;
326 
327 	if (fp->srf_response_len == 0)
328 		return (MIN(len, sizeof (smp_report_phy_error_log_resp_t)));
329 
330 	return (MIN(len, 4 * (fp->srf_response_len)));
331 }
332 
333 /*ARGSUSED*/
334 static size_t
335 sas2_report_phy_sata_rq_len(size_t user, smp_target_t *tp)
336 {
337 	if (user != 0) {
338 		(void) smp_set_errno(ESMP_RANGE);
339 		return (0);
340 	}
341 
342 	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_sata_req_t));
343 }
344 
345 /*ARGSUSED*/
346 static size_t
347 sas2_report_phy_sata_rs_datalen(smp_action_t *ap, smp_target_t *tp)
348 {
349 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
350 	smp_response_frame_t *fp;
351 	size_t len;
352 
353 	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_PHY_SATA);
354 	smp_action_get_response_frame(ap, (void **)&fp, &len);
355 
356 	if (len >= SMP_RESP_MINLEN)
357 		len -= SMP_RESP_MINLEN;
358 	else
359 		return (0);
360 
361 	len &= ~3;
362 
363 	if (fp->srf_response_len == 0)
364 		return (MIN(len, 52));
365 
366 	return (MIN(len, 4 * (fp->srf_response_len)));
367 }
368 
369 /*ARGSUSED*/
370 static size_t
371 sas2_report_route_info_rq_len(size_t user, smp_target_t *tp)
372 {
373 	if (user != 0) {
374 		(void) smp_set_errno(ESMP_RANGE);
375 		return (0);
376 	}
377 
378 	return (SMP_REQ_MINLEN + sizeof (smp_report_route_info_req_t));
379 }
380 
381 /*ARGSUSED*/
382 static size_t
383 sas2_report_route_info_rs_datalen(smp_action_t *ap, smp_target_t *tp)
384 {
385 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
386 	smp_response_frame_t *fp;
387 	size_t len;
388 
389 	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_ROUTE_INFO);
390 	smp_action_get_response_frame(ap, (void **)&fp, &len);
391 
392 	if (len >= SMP_RESP_MINLEN)
393 		len -= SMP_RESP_MINLEN;
394 	else
395 		return (0);
396 
397 	len &= ~3;
398 
399 	if (fp->srf_response_len == 0)
400 		return (MIN(len, sizeof (smp_report_route_info_resp_t)));
401 
402 	return (MIN(len, 4 * (fp->srf_response_len)));
403 }
404 
405 /*ARGSUSED*/
406 static size_t
407 sas2_report_phy_event_rq_len(size_t user, smp_target_t *tp)
408 {
409 	if (user != 0) {
410 		(void) smp_set_errno(ESMP_RANGE);
411 		return (0);
412 	}
413 
414 	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_event_req_t));
415 }
416 
417 /*ARGSUSED*/
418 static size_t
419 sas2_discover_list_rq_len(size_t user, smp_target_t *tp)
420 {
421 	if (user != 0) {
422 		(void) smp_set_errno(ESMP_RANGE);
423 		return (0);
424 	}
425 
426 	return (SMP_REQ_MINLEN + sizeof (smp_discover_list_req_t));
427 }
428 
429 /*ARGSUSED*/
430 static size_t
431 sas2_report_phy_event_list_rq_len(size_t user, smp_target_t *tp)
432 {
433 	if (user != 0) {
434 		(void) smp_set_errno(ESMP_RANGE);
435 		return (0);
436 	}
437 
438 	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_event_list_req_t));
439 }
440 
441 /*ARGSUSED*/
442 static size_t
443 sas2_report_exp_route_table_list_rq_len(size_t user, smp_target_t *tp)
444 {
445 	if (user != 0) {
446 		(void) smp_set_errno(ESMP_RANGE);
447 		return (0);
448 	}
449 
450 	return (SMP_REQ_MINLEN +
451 	    sizeof (smp_report_exp_route_table_list_req_t));
452 }
453 
454 /*ARGSUSED*/
455 static size_t
456 sas2_config_general_rq_len(size_t user, smp_target_t *tp)
457 {
458 	if (user != 0) {
459 		(void) smp_set_errno(ESMP_RANGE);
460 		return (0);
461 	}
462 
463 	return (SMP_REQ_MINLEN + sizeof (smp_config_general_req_t));
464 }
465 
466 /*ARGSUSED*/
467 static size_t
468 sas2_enable_disable_zoning_rq_len(size_t user, smp_target_t *tp)
469 {
470 	if (user != 0) {
471 		(void) smp_set_errno(ESMP_RANGE);
472 		return (0);
473 	}
474 
475 	return (SMP_REQ_MINLEN + sizeof (smp_enable_disable_zoning_req_t));
476 }
477 
478 /*ARGSUSED*/
479 static size_t
480 sas2_zoned_broadcast_rq_len(size_t user, smp_target_t *tp)
481 {
482 	size_t descrsz;
483 
484 	if (user == 0 || user > 1008) {
485 		(void) smp_set_errno(ESMP_RANGE);
486 		return (0);
487 	}
488 
489 	descrsz = P2ROUNDUP((user - 1), 4);
490 
491 	return (SMP_REQ_MINLEN + descrsz + sizeof (smp_zoned_broadcast_req_t));
492 }
493 
494 /*ARGSUSED*/
495 static size_t
496 sas2_zone_lock_rq_len(size_t user, smp_target_t *tp)
497 {
498 	if (user != 0) {
499 		(void) smp_set_errno(ESMP_RANGE);
500 		return (0);
501 	}
502 
503 	return (SMP_REQ_MINLEN + sizeof (smp_zone_lock_req_t));
504 }
505 
506 /*ARGSUSED*/
507 static size_t
508 sas2_zone_activate_rq_len(size_t user, smp_target_t *tp)
509 {
510 	if (user != 0) {
511 		(void) smp_set_errno(ESMP_RANGE);
512 		return (0);
513 	}
514 
515 	return (SMP_REQ_MINLEN + sizeof (smp_zone_activate_req_t));
516 }
517 
518 /*ARGSUSED*/
519 static size_t
520 sas2_zone_unlock_rq_len(size_t user, smp_target_t *tp)
521 {
522 	if (user != 0) {
523 		(void) smp_set_errno(ESMP_RANGE);
524 		return (0);
525 	}
526 
527 	return (SMP_REQ_MINLEN + sizeof (smp_zone_unlock_req_t));
528 }
529 
530 /*ARGSUSED*/
531 static size_t
532 sas2_config_zone_manager_password_rq_len(size_t user, smp_target_t *tp)
533 {
534 	if (user != 0) {
535 		(void) smp_set_errno(ESMP_RANGE);
536 		return (0);
537 	}
538 
539 	return (SMP_REQ_MINLEN +
540 	    sizeof (smp_config_zone_manager_password_req_t));
541 }
542 
543 /*ARGSUSED*/
544 static size_t
545 sas2_config_zone_phy_info_rq_len(size_t user, smp_target_t *tp)
546 {
547 	if (user == 0 || user > 252) {
548 		(void) smp_set_errno(ESMP_RANGE);
549 		return (0);
550 	}
551 
552 	return (SMP_REQ_MINLEN + sizeof (smp_config_zone_phy_info_req_t) +
553 	    (user - 1) * sizeof (smp_zone_phy_config_descr_t));
554 }
555 
556 static size_t
557 sas2_config_zone_perm_table_rq_len(size_t user, smp_target_t *tp)
558 {
559 	uint_t cap = smp_target_getcap(tp);
560 	size_t maxdescr, descrsz;
561 
562 	if (cap & SMP_TARGET_C_ZG_256)
563 		descrsz = sizeof (smp_zone_perm_descr256_t);
564 	else
565 		descrsz = sizeof (smp_zone_perm_descr128_t);
566 
567 	maxdescr = (1020 - sizeof (smp_config_zone_perm_table_req_t)) / descrsz;
568 
569 	if (user == 0 || user > maxdescr) {
570 		(void) smp_set_errno(ESMP_RANGE);
571 		return (0);
572 	}
573 
574 	return (SMP_REQ_MINLEN + sizeof (smp_config_zone_perm_table_req_t) - 1 +
575 	    user * descrsz);
576 }
577 
578 /*ARGSUSED*/
579 static size_t
580 sas2_config_route_info_rq_len(size_t user, smp_target_t *tp)
581 {
582 	if (user != 0) {
583 		(void) smp_set_errno(ESMP_RANGE);
584 		return (0);
585 	}
586 
587 	return (SMP_REQ_MINLEN + sizeof (smp_config_route_info_req_t));
588 }
589 
590 /*ARGSUSED*/
591 static size_t
592 sas2_phy_control_rq_len(size_t user, smp_target_t *tp)
593 {
594 	if (user != 0) {
595 		(void) smp_set_errno(ESMP_RANGE);
596 		return (0);
597 	}
598 
599 	return (SMP_REQ_MINLEN + sizeof (smp_phy_control_req_t));
600 }
601 
602 /*ARGSUSED*/
603 static size_t
604 sas2_phy_test_function_rq_len(size_t user, smp_target_t *tp)
605 {
606 	if (user != 0) {
607 		(void) smp_set_errno(ESMP_RANGE);
608 		return (0);
609 	}
610 
611 	return (SMP_REQ_MINLEN + sizeof (smp_phy_test_function_req_t));
612 }
613 
614 /*ARGSUSED*/
615 static size_t
616 sas2_config_phy_event_rq_len(size_t user, smp_target_t *tp)
617 {
618 	if (user == 0 || user > 126) {
619 		(void) smp_set_errno(ESMP_RANGE);
620 		return (0);
621 	}
622 
623 	return (SMP_REQ_MINLEN + sizeof (smp_config_phy_event_req_t) +
624 	    (user - 1) * sizeof (smp_phy_event_config_descr_t));
625 }
626 
627 smp_function_def_t sas2_functions[] = {
628 {
629 	.sfd_function = SMP_FUNC_REPORT_GENERAL,
630 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
631 	.sfd_rq_len = sas2_rq_len,
632 	.sfd_rq_dataoff = sas2_rq_dataoff,
633 	.sfd_rq_setframe = sas2_rq_setframe,
634 	.sfd_rs_datalen = sas2_report_general_rs_datalen,
635 	.sfd_rs_dataoff = sas2_rs_dataoff,
636 	.sfd_rs_getparams = sas2_rs_getparams
637 },
638 {
639 	.sfd_function = SMP_FUNC_REPORT_MANUFACTURER_INFO,
640 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
641 	.sfd_rq_len = sas2_rq_len,
642 	.sfd_rq_dataoff = sas2_rq_dataoff,
643 	.sfd_rq_setframe = sas2_rq_setframe,
644 	.sfd_rs_datalen = sas2_report_manufacturer_info_rs_datalen,
645 	.sfd_rs_dataoff = sas2_rs_dataoff,
646 	.sfd_rs_getparams = sas2_rs_getparams
647 },
648 {
649 	.sfd_function = SMP_FUNC_REPORT_SELF_CONFIG_STATUS,
650 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
651 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
652 	.sfd_rq_len = sas2_report_self_config_status_rq_len,
653 	.sfd_rq_dataoff = sas2_rq_dataoff,
654 	.sfd_rq_setframe = sas2_rq_setframe,
655 	.sfd_rs_datalen = sas2_rs_datalen,
656 	.sfd_rs_dataoff = sas2_rs_dataoff,
657 	.sfd_rs_getparams = sas2_rs_getparams
658 },
659 {
660 	.sfd_function = SMP_FUNC_REPORT_ZONE_PERM_TABLE,
661 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
662 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
663 	.sfd_rq_len = sas2_report_zone_perm_table_rq_len,
664 	.sfd_rq_dataoff = sas2_rq_dataoff,
665 	.sfd_rq_setframe = sas2_rq_setframe,
666 	.sfd_rs_datalen = sas2_rs_datalen,
667 	.sfd_rs_dataoff = sas2_rs_dataoff,
668 	.sfd_rs_getparams = sas2_rs_getparams
669 },
670 {
671 	.sfd_function = SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD,
672 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
673 	.sfd_rq_len = sas2_report_zone_mgr_password_rq_len,
674 	.sfd_rq_dataoff = sas2_rq_dataoff,
675 	.sfd_rq_setframe = sas2_rq_setframe,
676 	.sfd_rs_datalen = sas2_rs_datalen,
677 	.sfd_rs_dataoff = sas2_rs_dataoff,
678 	.sfd_rs_getparams = sas2_rs_getparams
679 },
680 {
681 	.sfd_function = SMP_FUNC_REPORT_BROADCAST,
682 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
683 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
684 	.sfd_rq_len = sas2_report_broadcast_rq_len,
685 	.sfd_rq_dataoff = sas2_rq_dataoff,
686 	.sfd_rq_setframe = sas2_rq_setframe,
687 	.sfd_rs_datalen = sas2_rs_datalen,
688 	.sfd_rs_dataoff = sas2_rs_dataoff,
689 	.sfd_rs_getparams = sas2_rs_getparams
690 },
691 {
692 	.sfd_function = SMP_FUNC_DISCOVER,
693 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
694 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
695 	.sfd_rq_len = sas2_discover_rq_len,
696 	.sfd_rq_dataoff = sas2_rq_dataoff,
697 	.sfd_rq_setframe = sas2_rq_setframe,
698 	.sfd_rs_datalen = sas2_discover_rs_datalen,
699 	.sfd_rs_dataoff = sas2_rs_dataoff,
700 	.sfd_rs_getparams = sas2_rs_getparams
701 },
702 {
703 	.sfd_function = SMP_FUNC_REPORT_PHY_ERROR_LOG,
704 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
705 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
706 	.sfd_rq_len = sas2_report_phy_error_log_rq_len,
707 	.sfd_rq_dataoff = sas2_rq_dataoff,
708 	.sfd_rq_setframe = sas2_rq_setframe,
709 	.sfd_rs_datalen = sas2_report_phy_error_log_rs_datalen,
710 	.sfd_rs_dataoff = sas2_rs_dataoff,
711 	.sfd_rs_getparams = sas2_rs_getparams
712 },
713 {
714 	.sfd_function = SMP_FUNC_REPORT_PHY_SATA,
715 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
716 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
717 	.sfd_rq_len = sas2_report_phy_sata_rq_len,
718 	.sfd_rq_dataoff = sas2_rq_dataoff,
719 	.sfd_rq_setframe = sas2_rq_setframe,
720 	.sfd_rs_datalen = sas2_report_phy_sata_rs_datalen,
721 	.sfd_rs_dataoff = sas2_rs_dataoff,
722 	.sfd_rs_getparams = sas2_rs_getparams
723 },
724 {
725 	.sfd_function = SMP_FUNC_REPORT_ROUTE_INFO,
726 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
727 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
728 	.sfd_rq_len = sas2_report_route_info_rq_len,
729 	.sfd_rq_dataoff = sas2_rq_dataoff,
730 	.sfd_rq_setframe = sas2_rq_setframe,
731 	.sfd_rs_datalen = sas2_report_route_info_rs_datalen,
732 	.sfd_rs_dataoff = sas2_rs_dataoff,
733 	.sfd_rs_getparams = sas2_rs_getparams
734 },
735 {
736 	.sfd_function = SMP_FUNC_REPORT_PHY_EVENT,
737 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
738 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
739 	.sfd_rq_len = sas2_report_phy_event_rq_len,
740 	.sfd_rq_dataoff = sas2_rq_dataoff,
741 	.sfd_rq_setframe = sas2_rq_setframe,
742 	.sfd_rs_datalen = sas2_rs_datalen,
743 	.sfd_rs_dataoff = sas2_rs_dataoff,
744 	.sfd_rs_getparams = sas2_rs_getparams
745 },
746 {
747 	.sfd_function = SMP_FUNC_DISCOVER_LIST,
748 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
749 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
750 	.sfd_rq_len = sas2_discover_list_rq_len,
751 	.sfd_rq_dataoff = sas2_rq_dataoff,
752 	.sfd_rq_setframe = sas2_rq_setframe,
753 	.sfd_rs_datalen = sas2_rs_datalen,
754 	.sfd_rs_dataoff = sas2_rs_dataoff,
755 	.sfd_rs_getparams = sas2_rs_getparams
756 },
757 {
758 	.sfd_function = SMP_FUNC_REPORT_PHY_EVENT_LIST,
759 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
760 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
761 	.sfd_rq_len = sas2_report_phy_event_list_rq_len,
762 	.sfd_rq_dataoff = sas2_rq_dataoff,
763 	.sfd_rq_setframe = sas2_rq_setframe,
764 	.sfd_rs_datalen = sas2_rs_datalen,
765 	.sfd_rs_dataoff = sas2_rs_dataoff,
766 	.sfd_rs_getparams = sas2_rs_getparams
767 },
768 {
769 	.sfd_function = SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST,
770 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
771 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
772 	.sfd_rq_len = sas2_report_exp_route_table_list_rq_len,
773 	.sfd_rq_dataoff = sas2_rq_dataoff,
774 	.sfd_rq_setframe = sas2_rq_setframe,
775 	.sfd_rs_datalen = sas2_rs_datalen,
776 	.sfd_rs_dataoff = sas2_rs_dataoff,
777 	.sfd_rs_getparams = sas2_rs_getparams
778 },
779 {
780 	.sfd_function = SMP_FUNC_CONFIG_GENERAL,
781 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
782 	.sfd_rq_len = sas2_config_general_rq_len,
783 	.sfd_rq_dataoff = sas2_rq_dataoff,
784 	.sfd_rq_setframe = sas2_rq_setframe,
785 	.sfd_rs_datalen = sas2_rs_datalen,
786 	.sfd_rs_dataoff = sas2_rs_dataoff,
787 	.sfd_rs_getparams = sas2_rs_getparams
788 },
789 {
790 	.sfd_function = SMP_FUNC_ENABLE_DISABLE_ZONING,
791 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
792 	.sfd_rq_len = sas2_enable_disable_zoning_rq_len,
793 	.sfd_rq_dataoff = sas2_rq_dataoff,
794 	.sfd_rq_setframe = sas2_rq_setframe,
795 	.sfd_rs_datalen = sas2_rs_datalen,
796 	.sfd_rs_dataoff = sas2_rs_dataoff,
797 	.sfd_rs_getparams = sas2_rs_getparams
798 },
799 {
800 	.sfd_function = SMP_FUNC_ZONED_BROADCAST,
801 	.sfd_flags = SMP_FD_F_WRITE,
802 	.sfd_rq_len = sas2_zoned_broadcast_rq_len,
803 	.sfd_rq_dataoff = sas2_rq_dataoff,
804 	.sfd_rq_setframe = sas2_rq_setframe,
805 	.sfd_rs_datalen = sas2_rs_datalen,
806 	.sfd_rs_dataoff = sas2_rs_dataoff,
807 	.sfd_rs_getparams = sas2_rs_getparams
808 },
809 {
810 	.sfd_function = SMP_FUNC_ZONE_LOCK,
811 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
812 	    SMP_FD_F_NEEDS_CHANGE_COUNT,
813 	.sfd_rq_len = sas2_zone_lock_rq_len,
814 	.sfd_rq_dataoff = sas2_rq_dataoff,
815 	.sfd_rq_setframe = sas2_rq_setframe,
816 	.sfd_rs_datalen = sas2_rs_datalen,
817 	.sfd_rs_dataoff = sas2_rs_dataoff,
818 	.sfd_rs_getparams = sas2_rs_getparams
819 },
820 {
821 	.sfd_function = SMP_FUNC_ZONE_ACTIVATE,
822 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
823 	.sfd_rq_len = sas2_zone_activate_rq_len,
824 	.sfd_rq_dataoff = sas2_rq_dataoff,
825 	.sfd_rq_setframe = sas2_rq_setframe,
826 	.sfd_rs_datalen = sas2_rs_datalen,
827 	.sfd_rs_dataoff = sas2_rs_dataoff,
828 	.sfd_rs_getparams = sas2_rs_getparams
829 },
830 {
831 	.sfd_function = SMP_FUNC_ZONE_UNLOCK,
832 	.sfd_flags = SMP_FD_F_WRITE,
833 	.sfd_rq_len = sas2_zone_unlock_rq_len,
834 	.sfd_rq_dataoff = sas2_rq_dataoff,
835 	.sfd_rq_setframe = sas2_rq_setframe,
836 	.sfd_rs_datalen = sas2_rs_datalen,
837 	.sfd_rs_dataoff = sas2_rs_dataoff,
838 	.sfd_rs_getparams = sas2_rs_getparams
839 },
840 {
841 	.sfd_function = SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD,
842 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
843 	.sfd_rq_len = sas2_config_zone_manager_password_rq_len,
844 	.sfd_rq_dataoff = sas2_rq_dataoff,
845 	.sfd_rq_setframe = sas2_rq_setframe,
846 	.sfd_rs_datalen = sas2_rs_datalen,
847 	.sfd_rs_dataoff = sas2_rs_dataoff,
848 	.sfd_rs_getparams = sas2_rs_getparams
849 },
850 {
851 	.sfd_function = SMP_FUNC_CONFIG_ZONE_PHY_INFO,
852 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
853 	.sfd_rq_len = sas2_config_zone_phy_info_rq_len,
854 	.sfd_rq_dataoff = sas2_rq_dataoff,
855 	.sfd_rq_setframe = sas2_rq_setframe,
856 	.sfd_rs_datalen = sas2_rs_datalen,
857 	.sfd_rs_dataoff = sas2_rs_dataoff,
858 	.sfd_rs_getparams = sas2_rs_getparams
859 },
860 {
861 	.sfd_function = SMP_FUNC_CONFIG_ZONE_PERM_TABLE,
862 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
863 	.sfd_rq_len = sas2_config_zone_perm_table_rq_len,
864 	.sfd_rq_dataoff = sas2_rq_dataoff,
865 	.sfd_rq_setframe = sas2_rq_setframe,
866 	.sfd_rs_datalen = sas2_rs_datalen,
867 	.sfd_rs_dataoff = sas2_rs_dataoff,
868 	.sfd_rs_getparams = sas2_rs_getparams
869 },
870 {
871 	.sfd_function = SMP_FUNC_CONFIG_ROUTE_INFO,
872 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
873 	.sfd_rq_len = sas2_config_route_info_rq_len,
874 	.sfd_rq_dataoff = sas2_rq_dataoff,
875 	.sfd_rq_setframe = sas2_rq_setframe,
876 	.sfd_rs_datalen = sas2_rs_datalen,
877 	.sfd_rs_dataoff = sas2_rs_dataoff,
878 	.sfd_rs_getparams = sas2_rs_getparams
879 },
880 {
881 	.sfd_function = SMP_FUNC_PHY_CONTROL,
882 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
883 	.sfd_rq_len = sas2_phy_control_rq_len,
884 	.sfd_rq_dataoff = sas2_rq_dataoff,
885 	.sfd_rq_setframe = sas2_rq_setframe,
886 	.sfd_rs_datalen = sas2_rs_datalen,
887 	.sfd_rs_dataoff = sas2_rs_dataoff,
888 	.sfd_rs_getparams = sas2_rs_getparams
889 },
890 {
891 	.sfd_function = SMP_FUNC_PHY_TEST_FUNCTION,
892 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
893 	.sfd_rq_len = sas2_phy_test_function_rq_len,
894 	.sfd_rq_dataoff = sas2_rq_dataoff,
895 	.sfd_rq_setframe = sas2_rq_setframe,
896 	.sfd_rs_datalen = sas2_rs_datalen,
897 	.sfd_rs_dataoff = sas2_rs_dataoff,
898 	.sfd_rs_getparams = sas2_rs_getparams
899 },
900 {
901 	.sfd_function = SMP_FUNC_CONFIG_PHY_EVENT,
902 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
903 	.sfd_rq_len = sas2_config_phy_event_rq_len,
904 	.sfd_rq_dataoff = sas2_rq_dataoff,
905 	.sfd_rq_setframe = sas2_rq_setframe,
906 	.sfd_rs_datalen = sas2_rs_datalen,
907 	.sfd_rs_dataoff = sas2_rs_dataoff,
908 	.sfd_rs_getparams = sas2_rs_getparams
909 },
910 {
911 	.sfd_function = -1
912 }
913 };
914 
915 /*
916  * Returns the number of bytes in the request frame, including the header
917  * and footer, for the given function and capabilities.  Presently the only
918  * relevant capability is long-request, which in some cases increases the
919  * size of the request from the SAS-1 spec to that found in SAS-2.
920  *
921  * Variably-sized request frames have no default size; we return 0 in that
922  * case, which will often be interpreted by the caller as an error although
923  * in general it is not.
924  */
925 size_t
926 smp_default_request_len(uint_t cap, smp_function_t fn)
927 {
928 	switch (fn) {
929 	case SMP_FUNC_REPORT_GENERAL:
930 	case SMP_FUNC_REPORT_MANUFACTURER_INFO:
931 		return (SMP_REQ_MINLEN);
932 	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
933 		return (SMP_REQ_MINLEN +
934 		    sizeof (smp_report_zone_mgr_password_req_t));
935 	case SMP_FUNC_REPORT_SELF_CONFIG_STATUS:
936 		if (cap & SMP_TARGET_C_LONG_RESP)
937 			return (SMP_REQ_MINLEN +
938 			    sizeof (smp_report_self_config_status_req_t));
939 		return (SMP_REQ_MINLEN);
940 	case SMP_FUNC_REPORT_ZONE_PERM_TABLE:
941 		if (cap & SMP_TARGET_C_LONG_RESP)
942 			return (SMP_REQ_MINLEN +
943 			    sizeof (smp_report_zone_perm_table_req_t));
944 		return (SMP_REQ_MINLEN);
945 	case SMP_FUNC_REPORT_BROADCAST:
946 		if (cap & SMP_TARGET_C_LONG_RESP)
947 			return (SMP_REQ_MINLEN +
948 			    sizeof (smp_report_broadcast_req_t));
949 		return (SMP_REQ_MINLEN);
950 	case SMP_FUNC_DISCOVER:
951 		return (SMP_REQ_MINLEN + sizeof (smp_discover_req_t));
952 	case SMP_FUNC_REPORT_PHY_ERROR_LOG:
953 		return (SMP_REQ_MINLEN +
954 		    sizeof (smp_report_phy_error_log_req_t));
955 	case SMP_FUNC_REPORT_PHY_SATA:
956 		return (SMP_REQ_MINLEN + sizeof (smp_report_phy_sata_req_t));
957 	case SMP_FUNC_REPORT_ROUTE_INFO:
958 		return (SMP_REQ_MINLEN + sizeof (smp_report_route_info_req_t));
959 	case SMP_FUNC_REPORT_PHY_EVENT:
960 		if (cap & SMP_TARGET_C_LONG_RESP)
961 			return (SMP_REQ_MINLEN +
962 			    sizeof (smp_report_phy_event_req_t));
963 		return (SMP_REQ_MINLEN);
964 	case SMP_FUNC_DISCOVER_LIST:
965 		if (cap & SMP_TARGET_C_LONG_RESP)
966 			return (SMP_REQ_MINLEN +
967 			    sizeof (smp_discover_list_req_t));
968 		return (SMP_REQ_MINLEN);
969 	case SMP_FUNC_REPORT_PHY_EVENT_LIST:
970 		if (cap & SMP_TARGET_C_LONG_RESP)
971 			return (SMP_REQ_MINLEN +
972 			    sizeof (smp_report_phy_event_list_req_t));
973 		return (SMP_REQ_MINLEN);
974 	case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST:
975 		if (cap & SMP_TARGET_C_LONG_RESP)
976 			return (SMP_REQ_MINLEN +
977 			    sizeof (smp_report_exp_route_table_list_req_t));
978 		return (SMP_REQ_MINLEN);
979 	case SMP_FUNC_CONFIG_GENERAL:
980 		if (cap & SMP_TARGET_C_LONG_RESP)
981 			return (SMP_REQ_MINLEN +
982 			    sizeof (smp_config_general_req_t));
983 		return (SMP_REQ_MINLEN);
984 	case SMP_FUNC_ENABLE_DISABLE_ZONING:
985 		if (cap & SMP_TARGET_C_LONG_RESP)
986 			return (SMP_REQ_MINLEN +
987 			    sizeof (smp_enable_disable_zoning_req_t));
988 		return (SMP_REQ_MINLEN);
989 	case SMP_FUNC_ZONE_LOCK:
990 		if (cap & SMP_TARGET_C_LONG_RESP)
991 			return (SMP_REQ_MINLEN +
992 			    sizeof (smp_zone_lock_req_t));
993 		return (SMP_REQ_MINLEN);
994 	case SMP_FUNC_ZONE_ACTIVATE:
995 		if (cap & SMP_TARGET_C_LONG_RESP)
996 			return (SMP_REQ_MINLEN +
997 			    sizeof (smp_zone_activate_req_t));
998 		return (SMP_REQ_MINLEN);
999 	case SMP_FUNC_ZONE_UNLOCK:
1000 		if (cap & SMP_TARGET_C_LONG_RESP)
1001 			return (SMP_REQ_MINLEN +
1002 			    sizeof (smp_zone_unlock_req_t));
1003 		return (SMP_REQ_MINLEN);
1004 	case SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD:
1005 		if (cap & SMP_TARGET_C_LONG_RESP)
1006 			return (SMP_REQ_MINLEN +
1007 			    sizeof (smp_config_zone_manager_password_req_t));
1008 		return (SMP_REQ_MINLEN);
1009 	case SMP_FUNC_CONFIG_ROUTE_INFO:
1010 		return (SMP_REQ_MINLEN + sizeof (smp_config_route_info_req_t));
1011 	case SMP_FUNC_PHY_CONTROL:
1012 		return (SMP_REQ_MINLEN + sizeof (smp_phy_control_req_t));
1013 	case SMP_FUNC_PHY_TEST_FUNCTION:
1014 		return (SMP_REQ_MINLEN + sizeof (smp_phy_test_function_req_t));
1015 
1016 	case SMP_FUNC_ZONED_BROADCAST:
1017 	case SMP_FUNC_CONFIG_ZONE_PHY_INFO:
1018 	case SMP_FUNC_CONFIG_ZONE_PERM_TABLE:
1019 	case SMP_FUNC_CONFIG_PHY_EVENT:
1020 	default:
1021 		return (0);
1022 	}
1023 }
1024 
1025 /*
1026  * This is slightly different - return the length in bytes, including the
1027  * header and footer, to be assumed for the response frame type if the
1028  * length field is zero.  Since the length field will not be zero unless the
1029  * long response bit is clear or the target is buggy, we always assume that
1030  * the caller wants the size of the v1 frame.
1031  */
1032 /*ARGSUSED*/
1033 size_t
1034 smp_default_response_len(uint_t cap, smp_function_t fn)
1035 {
1036 	switch (fn) {
1037 	case SMP_FUNC_REPORT_SELF_CONFIG_STATUS:
1038 	case SMP_FUNC_REPORT_ZONE_PERM_TABLE:
1039 	case SMP_FUNC_REPORT_BROADCAST:
1040 	case SMP_FUNC_REPORT_PHY_EVENT:
1041 	case SMP_FUNC_DISCOVER_LIST:
1042 	case SMP_FUNC_REPORT_PHY_EVENT_LIST:
1043 	case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST:
1044 	case SMP_FUNC_CONFIG_GENERAL:
1045 	case SMP_FUNC_ENABLE_DISABLE_ZONING:
1046 	case SMP_FUNC_ZONED_BROADCAST:
1047 	case SMP_FUNC_ZONE_LOCK:
1048 	case SMP_FUNC_ZONE_ACTIVATE:
1049 	case SMP_FUNC_ZONE_UNLOCK:
1050 	case SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD:
1051 	case SMP_FUNC_CONFIG_ZONE_PHY_INFO:
1052 	case SMP_FUNC_CONFIG_ZONE_PERM_TABLE:
1053 	case SMP_FUNC_CONFIG_ROUTE_INFO:
1054 	case SMP_FUNC_PHY_CONTROL:
1055 	case SMP_FUNC_PHY_TEST_FUNCTION:
1056 	case SMP_FUNC_CONFIG_PHY_EVENT:
1057 		return (SMP_RESP_MINLEN);
1058 	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
1059 		return (SMP_RESP_MINLEN +
1060 		    sizeof (smp_report_zone_mgr_password_resp_t));
1061 	case SMP_FUNC_REPORT_GENERAL:
1062 		return (SMP_RESP_MINLEN + 24);
1063 	case SMP_FUNC_REPORT_MANUFACTURER_INFO:
1064 		return (SMP_RESP_MINLEN +
1065 		    sizeof (smp_report_manufacturer_info_resp_t));
1066 	case SMP_FUNC_DISCOVER:
1067 		return (SMP_RESP_MINLEN + 48);
1068 	case SMP_FUNC_REPORT_PHY_ERROR_LOG:
1069 		return (SMP_RESP_MINLEN +
1070 		    sizeof (smp_report_phy_error_log_resp_t));
1071 	case SMP_FUNC_REPORT_PHY_SATA:
1072 		return (SMP_RESP_MINLEN + 52);
1073 	case SMP_FUNC_REPORT_ROUTE_INFO:
1074 		return (SMP_RESP_MINLEN +
1075 		    sizeof (smp_report_route_info_resp_t));
1076 
1077 	default:
1078 		return (0);
1079 	}
1080 }
1081