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