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  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * SCSI simulator.
30  *
31  * For testing purposes, we need a way to simulate arbitrary SCSI responses.  A
32  * completely flexible SCSI simulation language would be a large undertaking,
33  * given the number of possible outcomes.  Instead, we opt for the simpler route
34  * of using a shared object which implements versions of these functions.
35  *
36  * If a shared object doesn't implement a given function, or if the function
37  * returns non-zero, then the simulator will provide a suitable response
38  * indicating the functionality isn't supported.
39  */
40 
41 #include <libdiskstatus.h>
42 
43 #include "ds_scsi.h"
44 #include "ds_scsi_sim.h"
45 
46 static int
47 check_invalid_code(int ret, void *rqbuf)
48 {
49 	if (ret != 0) {
50 		struct scsi_extended_sense *sensep = rqbuf;
51 
52 		sensep->es_key = KEY_ILLEGAL_REQUEST;
53 		sensep->es_add_len = 6;
54 		sensep->es_code = CODE_FMT_FIXED_CURRENT;
55 		sensep->es_add_code = ASC_INVALID_OPCODE;
56 		sensep->es_qual_code = ASCQ_INVALID_OPCODE;
57 		ret = -1;
58 	}
59 
60 	return (ret);
61 }
62 
63 typedef int (*scsi_mode_sense_f)(int, int, caddr_t, int, scsi_ms_header_t *,
64     void *, int *);
65 
66 int
67 simscsi_mode_sense(void *hdl, int page_code, int page_control,
68     caddr_t page_data, int page_size, scsi_ms_header_t *header,
69     void *rqbuf, int *rqblen)
70 {
71 	scsi_mode_sense_f dscsi_mode_sense;
72 	int ret = -1;
73 
74 	dscsi_mode_sense = (scsi_mode_sense_f)dlsym(hdl, "scsi_mode_sense");
75 
76 	if (dscsi_mode_sense != NULL)
77 		ret = (*dscsi_mode_sense)(page_code, page_control, page_data,
78 		    page_size, header, rqbuf, rqblen);
79 
80 	return (check_invalid_code(ret, rqbuf));
81 }
82 
83 typedef int (*scsi_mode_sense_10_f)(int, int, caddr_t, int,
84     scsi_ms_header_g1_t *, void *, int *);
85 
86 int
87 simscsi_mode_sense_10(void *hdl, int page_code, int page_control,
88     caddr_t page_data, int page_size, scsi_ms_header_g1_t *header,
89     void *rqbuf, int *rqblen)
90 {
91 	scsi_mode_sense_10_f dscsi_mode_sense_10;
92 	int ret = -1;
93 
94 	dscsi_mode_sense_10 = (scsi_mode_sense_10_f)dlsym(hdl,
95 	    "scsi_mode_sense_10");
96 
97 	if (dscsi_mode_sense_10 != NULL)
98 		ret = (*dscsi_mode_sense_10)(page_code, page_control, page_data,
99 		    page_size, header, rqbuf, rqblen);
100 
101 	return (check_invalid_code(ret, rqbuf));
102 }
103 
104 typedef int (*scsi_mode_select_f)(int, int, caddr_t, int, scsi_ms_header_t *,
105     void *, int *);
106 
107 int
108 simscsi_mode_select(void *hdl, int page_code, int options, caddr_t page_data,
109     int page_size, scsi_ms_header_t *header, void *rqbuf, int *rqblen)
110 {
111 	scsi_mode_select_f dscsi_mode_select;
112 	int ret = -1;
113 
114 	dscsi_mode_select = (scsi_mode_select_f)(dlsym(hdl,
115 	    "scsi_mode_select"));
116 
117 	if (dscsi_mode_select != NULL)
118 		ret = (*dscsi_mode_select)(page_code, options, page_data,
119 		    page_size, header, rqbuf, rqblen);
120 
121 	return (check_invalid_code(ret, rqbuf));
122 }
123 
124 typedef int (*scsi_mode_select_10_f)(int, int, caddr_t, int,
125     scsi_ms_header_g1_t *, void *, int *);
126 
127 int
128 simscsi_mode_select_10(void *hdl, int page_code, int options,
129     caddr_t page_data, int page_size, scsi_ms_header_g1_t *header,
130     void *rqbuf, int *rqblen)
131 {
132 	scsi_mode_select_10_f dscsi_mode_select_10;
133 	int ret = -1;
134 
135 	dscsi_mode_select_10 = (scsi_mode_select_10_f)dlsym(hdl,
136 	    "scsi_mode_select_10");
137 
138 	if (dscsi_mode_select_10 != NULL)
139 		ret = (*dscsi_mode_select_10)(page_code, options, page_data,
140 		    page_size, header, rqbuf, rqblen);
141 
142 	return (check_invalid_code(ret, rqbuf));
143 }
144 
145 typedef int (*scsi_log_sense_f)(int, int, caddr_t, int, void *, int *);
146 
147 int
148 simscsi_log_sense(void *hdl, int page_code, int page_control,
149     caddr_t page_data, int page_size, void *rqbuf, int *rqblen)
150 {
151 	scsi_log_sense_f dscsi_log_sense;
152 	int ret = -1;
153 
154 	dscsi_log_sense = (scsi_log_sense_f)dlsym(hdl, "scsi_log_sense");
155 
156 	if (dscsi_log_sense != NULL)
157 		ret = (*dscsi_log_sense)(page_code, page_control, page_data,
158 		    page_size, rqbuf, rqblen);
159 
160 	return (check_invalid_code(ret, rqbuf));
161 }
162 
163 typedef int (*scsi_request_sense_f)(caddr_t, int, void *, int *);
164 
165 int
166 simscsi_request_sense(void *hdl, caddr_t buf, int buflen,
167     void *rqbuf, int *rqblen)
168 {
169 	scsi_request_sense_f dscsi_request_sense;
170 	int ret = -1;
171 
172 	dscsi_request_sense = (scsi_request_sense_f)dlsym(hdl,
173 	    "scsi_request_sense");
174 
175 	if (dscsi_request_sense != NULL)
176 		ret = (*dscsi_request_sense)(buf, buflen, rqbuf, rqblen);
177 
178 	return (check_invalid_code(ret, rqbuf));
179 }
180