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_broadcast_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_broadcast_req_t));
247 }
248 
249 /*ARGSUSED*/
250 static size_t
251 sas2_discover_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_discover_req_t));
259 }
260 
261 /*ARGSUSED*/
262 static size_t
263 sas2_discover_rs_datalen(smp_action_t *ap, smp_target_t *tp)
264 {
265 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
266 	smp_response_frame_t *fp;
267 	size_t len;
268 
269 	ASSERT(dp->sfd_function == SMP_FUNC_DISCOVER);
270 	smp_action_get_response_frame(ap, (void **)&fp, &len);
271 
272 	if (len >= SMP_RESP_MINLEN)
273 		len -= SMP_RESP_MINLEN;
274 	else
275 		return (0);
276 
277 	len &= ~3;
278 
279 	if (fp->srf_response_len == 0)
280 		return (MIN(len, 48));
281 
282 	return (MIN(len, 4 * (fp->srf_response_len)));
283 }
284 
285 /*ARGSUSED*/
286 static size_t
287 sas2_report_phy_error_log_rq_len(size_t user, smp_target_t *tp)
288 {
289 	if (user != 0) {
290 		(void) smp_set_errno(ESMP_RANGE);
291 		return (0);
292 	}
293 
294 	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_error_log_req_t));
295 }
296 
297 /*ARGSUSED*/
298 static size_t
299 sas2_report_phy_error_log_rs_datalen(smp_action_t *ap, smp_target_t *tp)
300 {
301 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
302 	smp_response_frame_t *fp;
303 	size_t len;
304 
305 	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_PHY_ERROR_LOG);
306 	smp_action_get_response_frame(ap, (void **)&fp, &len);
307 
308 	if (len >= SMP_RESP_MINLEN)
309 		len -= SMP_RESP_MINLEN;
310 	else
311 		return (0);
312 
313 	len &= ~3;
314 
315 	if (fp->srf_response_len == 0)
316 		return (MIN(len, sizeof (smp_report_phy_error_log_resp_t)));
317 
318 	return (MIN(len, 4 * (fp->srf_response_len)));
319 }
320 
321 /*ARGSUSED*/
322 static size_t
323 sas2_report_phy_sata_rq_len(size_t user, smp_target_t *tp)
324 {
325 	if (user != 0) {
326 		(void) smp_set_errno(ESMP_RANGE);
327 		return (0);
328 	}
329 
330 	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_sata_req_t));
331 }
332 
333 /*ARGSUSED*/
334 static size_t
335 sas2_report_phy_sata_rs_datalen(smp_action_t *ap, smp_target_t *tp)
336 {
337 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
338 	smp_response_frame_t *fp;
339 	size_t len;
340 
341 	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_PHY_SATA);
342 	smp_action_get_response_frame(ap, (void **)&fp, &len);
343 
344 	if (len >= SMP_RESP_MINLEN)
345 		len -= SMP_RESP_MINLEN;
346 	else
347 		return (0);
348 
349 	len &= ~3;
350 
351 	if (fp->srf_response_len == 0)
352 		return (MIN(len, 52));
353 
354 	return (MIN(len, 4 * (fp->srf_response_len)));
355 }
356 
357 /*ARGSUSED*/
358 static size_t
359 sas2_report_route_info_rq_len(size_t user, smp_target_t *tp)
360 {
361 	if (user != 0) {
362 		(void) smp_set_errno(ESMP_RANGE);
363 		return (0);
364 	}
365 
366 	return (SMP_REQ_MINLEN + sizeof (smp_report_route_info_req_t));
367 }
368 
369 /*ARGSUSED*/
370 static size_t
371 sas2_report_route_info_rs_datalen(smp_action_t *ap, smp_target_t *tp)
372 {
373 	const smp_function_def_t *dp = smp_action_get_function_def(ap);
374 	smp_response_frame_t *fp;
375 	size_t len;
376 
377 	ASSERT(dp->sfd_function == SMP_FUNC_REPORT_ROUTE_INFO);
378 	smp_action_get_response_frame(ap, (void **)&fp, &len);
379 
380 	if (len >= SMP_RESP_MINLEN)
381 		len -= SMP_RESP_MINLEN;
382 	else
383 		return (0);
384 
385 	len &= ~3;
386 
387 	if (fp->srf_response_len == 0)
388 		return (MIN(len, sizeof (smp_report_route_info_resp_t)));
389 
390 	return (MIN(len, 4 * (fp->srf_response_len)));
391 }
392 
393 /*ARGSUSED*/
394 static size_t
395 sas2_report_phy_event_rq_len(size_t user, smp_target_t *tp)
396 {
397 	if (user != 0) {
398 		(void) smp_set_errno(ESMP_RANGE);
399 		return (0);
400 	}
401 
402 	return (SMP_REQ_MINLEN + sizeof (smp_report_phy_event_req_t));
403 }
404 
405 /*ARGSUSED*/
406 static size_t
407 sas2_discover_list_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_discover_list_req_t));
415 }
416 
417 /*ARGSUSED*/
418 static size_t
419 sas2_report_phy_event_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_report_phy_event_list_req_t));
427 }
428 
429 /*ARGSUSED*/
430 static size_t
431 sas2_report_exp_route_table_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 +
439 	    sizeof (smp_report_exp_route_table_list_req_t));
440 }
441 
442 /*ARGSUSED*/
443 static size_t
444 sas2_config_general_rq_len(size_t user, smp_target_t *tp)
445 {
446 	if (user != 0) {
447 		(void) smp_set_errno(ESMP_RANGE);
448 		return (0);
449 	}
450 
451 	return (SMP_REQ_MINLEN + sizeof (smp_config_general_req_t));
452 }
453 
454 /*ARGSUSED*/
455 static size_t
456 sas2_enable_disable_zoning_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_enable_disable_zoning_req_t));
464 }
465 
466 /*ARGSUSED*/
467 static size_t
468 sas2_zoned_broadcast_rq_len(size_t user, smp_target_t *tp)
469 {
470 	size_t descrsz;
471 
472 	if (user == 0 || user > 1008) {
473 		(void) smp_set_errno(ESMP_RANGE);
474 		return (0);
475 	}
476 
477 	descrsz = P2ROUNDUP((user - 1), 4);
478 
479 	return (SMP_REQ_MINLEN + descrsz + sizeof (smp_zoned_broadcast_req_t));
480 }
481 
482 /*ARGSUSED*/
483 static size_t
484 sas2_zone_lock_rq_len(size_t user, smp_target_t *tp)
485 {
486 	if (user != 0) {
487 		(void) smp_set_errno(ESMP_RANGE);
488 		return (0);
489 	}
490 
491 	return (SMP_REQ_MINLEN + sizeof (smp_zone_lock_req_t));
492 }
493 
494 /*ARGSUSED*/
495 static size_t
496 sas2_zone_activate_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_activate_req_t));
504 }
505 
506 /*ARGSUSED*/
507 static size_t
508 sas2_zone_unlock_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_unlock_req_t));
516 }
517 
518 /*ARGSUSED*/
519 static size_t
520 sas2_config_zone_manager_password_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 +
528 	    sizeof (smp_config_zone_manager_password_req_t));
529 }
530 
531 /*ARGSUSED*/
532 static size_t
533 sas2_config_zone_phy_info_rq_len(size_t user, smp_target_t *tp)
534 {
535 	if (user == 0 || user > 252) {
536 		(void) smp_set_errno(ESMP_RANGE);
537 		return (0);
538 	}
539 
540 	return (SMP_REQ_MINLEN + sizeof (smp_config_zone_phy_info_req_t) +
541 	    (user - 1) * sizeof (smp_zone_phy_config_descr_t));
542 }
543 
544 static size_t
545 sas2_config_zone_perm_table_rq_len(size_t user, smp_target_t *tp)
546 {
547 	uint_t cap = smp_target_getcap(tp);
548 	size_t maxdescr, descrsz;
549 
550 	if (cap & SMP_TARGET_C_ZG_256)
551 		descrsz = sizeof (smp_zone_perm_descr256_t);
552 	else
553 		descrsz = sizeof (smp_zone_perm_descr128_t);
554 
555 	maxdescr = (1020 - sizeof (smp_config_zone_perm_table_req_t)) / descrsz;
556 
557 	if (user == 0 || user > maxdescr) {
558 		(void) smp_set_errno(ESMP_RANGE);
559 		return (0);
560 	}
561 
562 	return (SMP_REQ_MINLEN + sizeof (smp_config_zone_perm_table_req_t) - 1 +
563 	    user * descrsz);
564 }
565 
566 /*ARGSUSED*/
567 static size_t
568 sas2_config_route_info_rq_len(size_t user, smp_target_t *tp)
569 {
570 	if (user != 0) {
571 		(void) smp_set_errno(ESMP_RANGE);
572 		return (0);
573 	}
574 
575 	return (SMP_REQ_MINLEN + sizeof (smp_config_route_info_req_t));
576 }
577 
578 /*ARGSUSED*/
579 static size_t
580 sas2_phy_control_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_phy_control_req_t));
588 }
589 
590 /*ARGSUSED*/
591 static size_t
592 sas2_phy_test_function_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_test_function_req_t));
600 }
601 
602 /*ARGSUSED*/
603 static size_t
604 sas2_config_phy_event_rq_len(size_t user, smp_target_t *tp)
605 {
606 	if (user == 0 || user > 126) {
607 		(void) smp_set_errno(ESMP_RANGE);
608 		return (0);
609 	}
610 
611 	return (SMP_REQ_MINLEN + sizeof (smp_config_phy_event_req_t) +
612 	    (user - 1) * sizeof (smp_phy_event_config_descr_t));
613 }
614 
615 smp_function_def_t sas2_functions[] = {
616 {
617 	.sfd_function = SMP_FUNC_REPORT_GENERAL,
618 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
619 	.sfd_rq_len = sas2_rq_len,
620 	.sfd_rq_dataoff = sas2_rq_dataoff,
621 	.sfd_rq_setframe = sas2_rq_setframe,
622 	.sfd_rs_datalen = sas2_report_general_rs_datalen,
623 	.sfd_rs_dataoff = sas2_rs_dataoff,
624 	.sfd_rs_getparams = sas2_rs_getparams
625 },
626 {
627 	.sfd_function = SMP_FUNC_REPORT_MANUFACTURER_INFO,
628 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
629 	.sfd_rq_len = sas2_rq_len,
630 	.sfd_rq_dataoff = sas2_rq_dataoff,
631 	.sfd_rq_setframe = sas2_rq_setframe,
632 	.sfd_rs_datalen = sas2_report_manufacturer_info_rs_datalen,
633 	.sfd_rs_dataoff = sas2_rs_dataoff,
634 	.sfd_rs_getparams = sas2_rs_getparams
635 },
636 {
637 	.sfd_function = SMP_FUNC_REPORT_SELF_CONFIG_STATUS,
638 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
639 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
640 	.sfd_rq_len = sas2_report_self_config_status_rq_len,
641 	.sfd_rq_dataoff = sas2_rq_dataoff,
642 	.sfd_rq_setframe = sas2_rq_setframe,
643 	.sfd_rs_datalen = sas2_rs_datalen,
644 	.sfd_rs_dataoff = sas2_rs_dataoff,
645 	.sfd_rs_getparams = sas2_rs_getparams
646 },
647 {
648 	.sfd_function = SMP_FUNC_REPORT_ZONE_PERM_TABLE,
649 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
650 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
651 	.sfd_rq_len = sas2_report_zone_perm_table_rq_len,
652 	.sfd_rq_dataoff = sas2_rq_dataoff,
653 	.sfd_rq_setframe = sas2_rq_setframe,
654 	.sfd_rs_datalen = sas2_rs_datalen,
655 	.sfd_rs_dataoff = sas2_rs_dataoff,
656 	.sfd_rs_getparams = sas2_rs_getparams
657 },
658 {
659 	.sfd_function = SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD,
660 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_PROVIDES_CHANGE_COUNT,
661 	.sfd_rq_len = sas2_rq_len,
662 	.sfd_rq_dataoff = sas2_rq_dataoff,
663 	.sfd_rq_setframe = sas2_rq_setframe,
664 	.sfd_rs_datalen = sas2_rs_datalen,
665 	.sfd_rs_dataoff = sas2_rs_dataoff,
666 	.sfd_rs_getparams = sas2_rs_getparams
667 },
668 {
669 	.sfd_function = SMP_FUNC_REPORT_BROADCAST,
670 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
671 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
672 	.sfd_rq_len = sas2_report_broadcast_rq_len,
673 	.sfd_rq_dataoff = sas2_rq_dataoff,
674 	.sfd_rq_setframe = sas2_rq_setframe,
675 	.sfd_rs_datalen = sas2_rs_datalen,
676 	.sfd_rs_dataoff = sas2_rs_dataoff,
677 	.sfd_rs_getparams = sas2_rs_getparams
678 },
679 {
680 	.sfd_function = SMP_FUNC_DISCOVER,
681 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
682 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
683 	.sfd_rq_len = sas2_discover_rq_len,
684 	.sfd_rq_dataoff = sas2_rq_dataoff,
685 	.sfd_rq_setframe = sas2_rq_setframe,
686 	.sfd_rs_datalen = sas2_discover_rs_datalen,
687 	.sfd_rs_dataoff = sas2_rs_dataoff,
688 	.sfd_rs_getparams = sas2_rs_getparams
689 },
690 {
691 	.sfd_function = SMP_FUNC_REPORT_PHY_ERROR_LOG,
692 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
693 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
694 	.sfd_rq_len = sas2_report_phy_error_log_rq_len,
695 	.sfd_rq_dataoff = sas2_rq_dataoff,
696 	.sfd_rq_setframe = sas2_rq_setframe,
697 	.sfd_rs_datalen = sas2_report_phy_error_log_rs_datalen,
698 	.sfd_rs_dataoff = sas2_rs_dataoff,
699 	.sfd_rs_getparams = sas2_rs_getparams
700 },
701 {
702 	.sfd_function = SMP_FUNC_REPORT_PHY_SATA,
703 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
704 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
705 	.sfd_rq_len = sas2_report_phy_sata_rq_len,
706 	.sfd_rq_dataoff = sas2_rq_dataoff,
707 	.sfd_rq_setframe = sas2_rq_setframe,
708 	.sfd_rs_datalen = sas2_report_phy_sata_rs_datalen,
709 	.sfd_rs_dataoff = sas2_rs_dataoff,
710 	.sfd_rs_getparams = sas2_rs_getparams
711 },
712 {
713 	.sfd_function = SMP_FUNC_REPORT_ROUTE_INFO,
714 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
715 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
716 	.sfd_rq_len = sas2_report_route_info_rq_len,
717 	.sfd_rq_dataoff = sas2_rq_dataoff,
718 	.sfd_rq_setframe = sas2_rq_setframe,
719 	.sfd_rs_datalen = sas2_report_route_info_rs_datalen,
720 	.sfd_rs_dataoff = sas2_rs_dataoff,
721 	.sfd_rs_getparams = sas2_rs_getparams
722 },
723 {
724 	.sfd_function = SMP_FUNC_REPORT_PHY_EVENT,
725 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
726 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
727 	.sfd_rq_len = sas2_report_phy_event_rq_len,
728 	.sfd_rq_dataoff = sas2_rq_dataoff,
729 	.sfd_rq_setframe = sas2_rq_setframe,
730 	.sfd_rs_datalen = sas2_rs_datalen,
731 	.sfd_rs_dataoff = sas2_rs_dataoff,
732 	.sfd_rs_getparams = sas2_rs_getparams
733 },
734 {
735 	.sfd_function = SMP_FUNC_DISCOVER_LIST,
736 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
737 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
738 	.sfd_rq_len = sas2_discover_list_rq_len,
739 	.sfd_rq_dataoff = sas2_rq_dataoff,
740 	.sfd_rq_setframe = sas2_rq_setframe,
741 	.sfd_rs_datalen = sas2_rs_datalen,
742 	.sfd_rs_dataoff = sas2_rs_dataoff,
743 	.sfd_rs_getparams = sas2_rs_getparams
744 },
745 {
746 	.sfd_function = SMP_FUNC_REPORT_PHY_EVENT_LIST,
747 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
748 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
749 	.sfd_rq_len = sas2_report_phy_event_list_rq_len,
750 	.sfd_rq_dataoff = sas2_rq_dataoff,
751 	.sfd_rq_setframe = sas2_rq_setframe,
752 	.sfd_rs_datalen = sas2_rs_datalen,
753 	.sfd_rs_dataoff = sas2_rs_dataoff,
754 	.sfd_rs_getparams = sas2_rs_getparams
755 },
756 {
757 	.sfd_function = SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST,
758 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
759 	    SMP_FD_F_PROVIDES_CHANGE_COUNT,
760 	.sfd_rq_len = sas2_report_exp_route_table_list_rq_len,
761 	.sfd_rq_dataoff = sas2_rq_dataoff,
762 	.sfd_rq_setframe = sas2_rq_setframe,
763 	.sfd_rs_datalen = sas2_rs_datalen,
764 	.sfd_rs_dataoff = sas2_rs_dataoff,
765 	.sfd_rs_getparams = sas2_rs_getparams
766 },
767 {
768 	.sfd_function = SMP_FUNC_CONFIG_GENERAL,
769 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
770 	.sfd_rq_len = sas2_config_general_rq_len,
771 	.sfd_rq_dataoff = sas2_rq_dataoff,
772 	.sfd_rq_setframe = sas2_rq_setframe,
773 	.sfd_rs_datalen = sas2_rs_datalen,
774 	.sfd_rs_dataoff = sas2_rs_dataoff,
775 	.sfd_rs_getparams = sas2_rs_getparams
776 },
777 {
778 	.sfd_function = SMP_FUNC_ENABLE_DISABLE_ZONING,
779 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
780 	.sfd_rq_len = sas2_enable_disable_zoning_rq_len,
781 	.sfd_rq_dataoff = sas2_rq_dataoff,
782 	.sfd_rq_setframe = sas2_rq_setframe,
783 	.sfd_rs_datalen = sas2_rs_datalen,
784 	.sfd_rs_dataoff = sas2_rs_dataoff,
785 	.sfd_rs_getparams = sas2_rs_getparams
786 },
787 {
788 	.sfd_function = SMP_FUNC_ZONED_BROADCAST,
789 	.sfd_flags = SMP_FD_F_WRITE,
790 	.sfd_rq_len = sas2_zoned_broadcast_rq_len,
791 	.sfd_rq_dataoff = sas2_rq_dataoff,
792 	.sfd_rq_setframe = sas2_rq_setframe,
793 	.sfd_rs_datalen = sas2_rs_datalen,
794 	.sfd_rs_dataoff = sas2_rs_dataoff,
795 	.sfd_rs_getparams = sas2_rs_getparams
796 },
797 {
798 	.sfd_function = SMP_FUNC_ZONE_LOCK,
799 	.sfd_flags = SMP_FD_F_READ | SMP_FD_F_WRITE |
800 	    SMP_FD_F_NEEDS_CHANGE_COUNT,
801 	.sfd_rq_len = sas2_zone_lock_rq_len,
802 	.sfd_rq_dataoff = sas2_rq_dataoff,
803 	.sfd_rq_setframe = sas2_rq_setframe,
804 	.sfd_rs_datalen = sas2_rs_datalen,
805 	.sfd_rs_dataoff = sas2_rs_dataoff,
806 	.sfd_rs_getparams = sas2_rs_getparams
807 },
808 {
809 	.sfd_function = SMP_FUNC_ZONE_ACTIVATE,
810 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
811 	.sfd_rq_len = sas2_zone_activate_rq_len,
812 	.sfd_rq_dataoff = sas2_rq_dataoff,
813 	.sfd_rq_setframe = sas2_rq_setframe,
814 	.sfd_rs_datalen = sas2_rs_datalen,
815 	.sfd_rs_dataoff = sas2_rs_dataoff,
816 	.sfd_rs_getparams = sas2_rs_getparams
817 },
818 {
819 	.sfd_function = SMP_FUNC_ZONE_UNLOCK,
820 	.sfd_flags = SMP_FD_F_WRITE,
821 	.sfd_rq_len = sas2_zone_unlock_rq_len,
822 	.sfd_rq_dataoff = sas2_rq_dataoff,
823 	.sfd_rq_setframe = sas2_rq_setframe,
824 	.sfd_rs_datalen = sas2_rs_datalen,
825 	.sfd_rs_dataoff = sas2_rs_dataoff,
826 	.sfd_rs_getparams = sas2_rs_getparams
827 },
828 {
829 	.sfd_function = SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD,
830 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
831 	.sfd_rq_len = sas2_config_zone_manager_password_rq_len,
832 	.sfd_rq_dataoff = sas2_rq_dataoff,
833 	.sfd_rq_setframe = sas2_rq_setframe,
834 	.sfd_rs_datalen = sas2_rs_datalen,
835 	.sfd_rs_dataoff = sas2_rs_dataoff,
836 	.sfd_rs_getparams = sas2_rs_getparams
837 },
838 {
839 	.sfd_function = SMP_FUNC_CONFIG_ZONE_PHY_INFO,
840 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
841 	.sfd_rq_len = sas2_config_zone_phy_info_rq_len,
842 	.sfd_rq_dataoff = sas2_rq_dataoff,
843 	.sfd_rq_setframe = sas2_rq_setframe,
844 	.sfd_rs_datalen = sas2_rs_datalen,
845 	.sfd_rs_dataoff = sas2_rs_dataoff,
846 	.sfd_rs_getparams = sas2_rs_getparams
847 },
848 {
849 	.sfd_function = SMP_FUNC_CONFIG_ZONE_PERM_TABLE,
850 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
851 	.sfd_rq_len = sas2_config_zone_perm_table_rq_len,
852 	.sfd_rq_dataoff = sas2_rq_dataoff,
853 	.sfd_rq_setframe = sas2_rq_setframe,
854 	.sfd_rs_datalen = sas2_rs_datalen,
855 	.sfd_rs_dataoff = sas2_rs_dataoff,
856 	.sfd_rs_getparams = sas2_rs_getparams
857 },
858 {
859 	.sfd_function = SMP_FUNC_CONFIG_ROUTE_INFO,
860 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
861 	.sfd_rq_len = sas2_config_route_info_rq_len,
862 	.sfd_rq_dataoff = sas2_rq_dataoff,
863 	.sfd_rq_setframe = sas2_rq_setframe,
864 	.sfd_rs_datalen = sas2_rs_datalen,
865 	.sfd_rs_dataoff = sas2_rs_dataoff,
866 	.sfd_rs_getparams = sas2_rs_getparams
867 },
868 {
869 	.sfd_function = SMP_FUNC_PHY_CONTROL,
870 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
871 	.sfd_rq_len = sas2_phy_control_rq_len,
872 	.sfd_rq_dataoff = sas2_rq_dataoff,
873 	.sfd_rq_setframe = sas2_rq_setframe,
874 	.sfd_rs_datalen = sas2_rs_datalen,
875 	.sfd_rs_dataoff = sas2_rs_dataoff,
876 	.sfd_rs_getparams = sas2_rs_getparams
877 },
878 {
879 	.sfd_function = SMP_FUNC_PHY_TEST_FUNCTION,
880 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
881 	.sfd_rq_len = sas2_phy_test_function_rq_len,
882 	.sfd_rq_dataoff = sas2_rq_dataoff,
883 	.sfd_rq_setframe = sas2_rq_setframe,
884 	.sfd_rs_datalen = sas2_rs_datalen,
885 	.sfd_rs_dataoff = sas2_rs_dataoff,
886 	.sfd_rs_getparams = sas2_rs_getparams
887 },
888 {
889 	.sfd_function = SMP_FUNC_CONFIG_PHY_EVENT,
890 	.sfd_flags = SMP_FD_F_WRITE | SMP_FD_F_NEEDS_CHANGE_COUNT,
891 	.sfd_rq_len = sas2_config_phy_event_rq_len,
892 	.sfd_rq_dataoff = sas2_rq_dataoff,
893 	.sfd_rq_setframe = sas2_rq_setframe,
894 	.sfd_rs_datalen = sas2_rs_datalen,
895 	.sfd_rs_dataoff = sas2_rs_dataoff,
896 	.sfd_rs_getparams = sas2_rs_getparams
897 },
898 {
899 	.sfd_function = -1
900 }
901 };
902 
903 /*
904  * Returns the number of bytes in the request frame, including the header
905  * and footer, for the given function and capabilities.  Presently the only
906  * relevant capability is long-request, which in some cases increases the
907  * size of the request from the SAS-1 spec to that found in SAS-2.
908  *
909  * Variably-sized request frames have no default size; we return 0 in that
910  * case, which will often be interpreted by the caller as an error although
911  * in general it is not.
912  */
913 size_t
914 smp_default_request_len(uint_t cap, smp_function_t fn)
915 {
916 	switch (fn) {
917 	case SMP_FUNC_REPORT_GENERAL:
918 	case SMP_FUNC_REPORT_MANUFACTURER_INFO:
919 	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
920 		return (SMP_REQ_MINLEN);
921 
922 	case SMP_FUNC_REPORT_SELF_CONFIG_STATUS:
923 		if (cap & SMP_TARGET_C_LONG_RESP)
924 			return (SMP_REQ_MINLEN +
925 			    sizeof (smp_report_self_config_status_req_t));
926 		return (SMP_REQ_MINLEN);
927 	case SMP_FUNC_REPORT_ZONE_PERM_TABLE:
928 		if (cap & SMP_TARGET_C_LONG_RESP)
929 			return (SMP_REQ_MINLEN +
930 			    sizeof (smp_report_zone_perm_table_req_t));
931 		return (SMP_REQ_MINLEN);
932 	case SMP_FUNC_REPORT_BROADCAST:
933 		if (cap & SMP_TARGET_C_LONG_RESP)
934 			return (SMP_REQ_MINLEN +
935 			    sizeof (smp_report_broadcast_req_t));
936 		return (SMP_REQ_MINLEN);
937 	case SMP_FUNC_DISCOVER:
938 		return (SMP_REQ_MINLEN + sizeof (smp_discover_req_t));
939 	case SMP_FUNC_REPORT_PHY_ERROR_LOG:
940 		return (SMP_REQ_MINLEN +
941 		    sizeof (smp_report_phy_error_log_req_t));
942 	case SMP_FUNC_REPORT_PHY_SATA:
943 		return (SMP_REQ_MINLEN + sizeof (smp_report_phy_sata_req_t));
944 	case SMP_FUNC_REPORT_ROUTE_INFO:
945 		return (SMP_REQ_MINLEN + sizeof (smp_report_route_info_req_t));
946 	case SMP_FUNC_REPORT_PHY_EVENT:
947 		if (cap & SMP_TARGET_C_LONG_RESP)
948 			return (SMP_REQ_MINLEN +
949 			    sizeof (smp_report_phy_event_req_t));
950 		return (SMP_REQ_MINLEN);
951 	case SMP_FUNC_DISCOVER_LIST:
952 		if (cap & SMP_TARGET_C_LONG_RESP)
953 			return (SMP_REQ_MINLEN +
954 			    sizeof (smp_discover_list_req_t));
955 		return (SMP_REQ_MINLEN);
956 	case SMP_FUNC_REPORT_PHY_EVENT_LIST:
957 		if (cap & SMP_TARGET_C_LONG_RESP)
958 			return (SMP_REQ_MINLEN +
959 			    sizeof (smp_report_phy_event_list_req_t));
960 		return (SMP_REQ_MINLEN);
961 	case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST:
962 		if (cap & SMP_TARGET_C_LONG_RESP)
963 			return (SMP_REQ_MINLEN +
964 			    sizeof (smp_report_exp_route_table_list_req_t));
965 		return (SMP_REQ_MINLEN);
966 	case SMP_FUNC_CONFIG_GENERAL:
967 		if (cap & SMP_TARGET_C_LONG_RESP)
968 			return (SMP_REQ_MINLEN +
969 			    sizeof (smp_config_general_req_t));
970 		return (SMP_REQ_MINLEN);
971 	case SMP_FUNC_ENABLE_DISABLE_ZONING:
972 		if (cap & SMP_TARGET_C_LONG_RESP)
973 			return (SMP_REQ_MINLEN +
974 			    sizeof (smp_enable_disable_zoning_req_t));
975 		return (SMP_REQ_MINLEN);
976 	case SMP_FUNC_ZONE_LOCK:
977 		if (cap & SMP_TARGET_C_LONG_RESP)
978 			return (SMP_REQ_MINLEN +
979 			    sizeof (smp_zone_lock_req_t));
980 		return (SMP_REQ_MINLEN);
981 	case SMP_FUNC_ZONE_ACTIVATE:
982 		if (cap & SMP_TARGET_C_LONG_RESP)
983 			return (SMP_REQ_MINLEN +
984 			    sizeof (smp_zone_activate_req_t));
985 		return (SMP_REQ_MINLEN);
986 	case SMP_FUNC_ZONE_UNLOCK:
987 		if (cap & SMP_TARGET_C_LONG_RESP)
988 			return (SMP_REQ_MINLEN +
989 			    sizeof (smp_zone_unlock_req_t));
990 		return (SMP_REQ_MINLEN);
991 	case SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD:
992 		if (cap & SMP_TARGET_C_LONG_RESP)
993 			return (SMP_REQ_MINLEN +
994 			    sizeof (smp_config_zone_manager_password_req_t));
995 		return (SMP_REQ_MINLEN);
996 	case SMP_FUNC_CONFIG_ROUTE_INFO:
997 		return (SMP_REQ_MINLEN + sizeof (smp_config_route_info_req_t));
998 	case SMP_FUNC_PHY_CONTROL:
999 		return (SMP_REQ_MINLEN + sizeof (smp_phy_control_req_t));
1000 	case SMP_FUNC_PHY_TEST_FUNCTION:
1001 		return (SMP_REQ_MINLEN + sizeof (smp_phy_test_function_req_t));
1002 
1003 	case SMP_FUNC_ZONED_BROADCAST:
1004 	case SMP_FUNC_CONFIG_ZONE_PHY_INFO:
1005 	case SMP_FUNC_CONFIG_ZONE_PERM_TABLE:
1006 	case SMP_FUNC_CONFIG_PHY_EVENT:
1007 	default:
1008 		return (0);
1009 	}
1010 }
1011 
1012 /*
1013  * This is slightly different - return the length in bytes, including the
1014  * header and footer, to be assumed for the response frame type if the
1015  * length field is zero.  Since the length field will not be zero unless the
1016  * long response bit is clear or the target is buggy, we always assume that
1017  * the caller wants the size of the v1 frame.
1018  */
1019 /*ARGSUSED*/
1020 size_t
1021 smp_default_response_len(uint_t cap, smp_function_t fn)
1022 {
1023 	switch (fn) {
1024 	case SMP_FUNC_REPORT_SELF_CONFIG_STATUS:
1025 	case SMP_FUNC_REPORT_ZONE_PERM_TABLE:
1026 	case SMP_FUNC_REPORT_ZONE_MANAGER_PASSWORD:
1027 	case SMP_FUNC_REPORT_BROADCAST:
1028 	case SMP_FUNC_REPORT_PHY_EVENT:
1029 	case SMP_FUNC_DISCOVER_LIST:
1030 	case SMP_FUNC_REPORT_PHY_EVENT_LIST:
1031 	case SMP_FUNC_REPORT_EXP_ROUTE_TABLE_LIST:
1032 	case SMP_FUNC_CONFIG_GENERAL:
1033 	case SMP_FUNC_ENABLE_DISABLE_ZONING:
1034 	case SMP_FUNC_ZONED_BROADCAST:
1035 	case SMP_FUNC_ZONE_LOCK:
1036 	case SMP_FUNC_ZONE_ACTIVATE:
1037 	case SMP_FUNC_ZONE_UNLOCK:
1038 	case SMP_FUNC_CONFIG_ZONE_MANAGER_PASSWORD:
1039 	case SMP_FUNC_CONFIG_ZONE_PHY_INFO:
1040 	case SMP_FUNC_CONFIG_ZONE_PERM_TABLE:
1041 	case SMP_FUNC_CONFIG_ROUTE_INFO:
1042 	case SMP_FUNC_PHY_CONTROL:
1043 	case SMP_FUNC_PHY_TEST_FUNCTION:
1044 	case SMP_FUNC_CONFIG_PHY_EVENT:
1045 		return (SMP_RESP_MINLEN);
1046 
1047 	case SMP_FUNC_REPORT_GENERAL:
1048 		return (SMP_RESP_MINLEN + 24);
1049 	case SMP_FUNC_REPORT_MANUFACTURER_INFO:
1050 		return (SMP_RESP_MINLEN +
1051 		    sizeof (smp_report_manufacturer_info_resp_t));
1052 	case SMP_FUNC_DISCOVER:
1053 		return (SMP_RESP_MINLEN + 48);
1054 	case SMP_FUNC_REPORT_PHY_ERROR_LOG:
1055 		return (SMP_RESP_MINLEN +
1056 		    sizeof (smp_report_phy_error_log_resp_t));
1057 	case SMP_FUNC_REPORT_PHY_SATA:
1058 		return (SMP_RESP_MINLEN + 52);
1059 	case SMP_FUNC_REPORT_ROUTE_INFO:
1060 		return (SMP_RESP_MINLEN +
1061 		    sizeof (smp_report_route_info_resp_t));
1062 
1063 	default:
1064 		return (0);
1065 	}
1066 }
1067