xref: /freebsd/sys/cam/cam_compat.c (revision 1f474190)
1 /*-
2  * CAM ioctl compatibility shims
3  *
4  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
5  *
6  * Copyright (c) 2013 Scott Long
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions, and the following disclaimer,
14  *    without modification, immediately at the beginning of the file.
15  * 2. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/types.h>
38 #include <sys/kernel.h>
39 #include <sys/conf.h>
40 #include <sys/fcntl.h>
41 
42 #include <sys/lock.h>
43 #include <sys/mutex.h>
44 #include <sys/sysctl.h>
45 #include <sys/kthread.h>
46 
47 #include <cam/cam.h>
48 #include <cam/cam_ccb.h>
49 #include <cam/cam_xpt.h>
50 #include <cam/cam_compat.h>
51 #include <cam/cam_periph.h>
52 
53 #include <cam/scsi/scsi_pass.h>
54 
55 #include "opt_cam.h"
56 
57 static int cam_compat_handle_0x17(struct cdev *dev, u_long cmd, caddr_t addr,
58     int flag, struct thread *td, d_ioctl_t *cbfnp);
59 static int cam_compat_handle_0x18(struct cdev *dev, u_long cmd, caddr_t addr,
60     int flag, struct thread *td, d_ioctl_t *cbfnp);
61 static int cam_compat_translate_dev_match_0x18(union ccb *ccb);
62 
63 int
64 cam_compat_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
65     struct thread *td, d_ioctl_t *cbfnp)
66 {
67 	int error;
68 
69 	switch (cmd) {
70 	case CAMIOCOMMAND_0x16:
71 	{
72 		struct ccb_hdr_0x17 *hdr17;
73 
74 		hdr17 = (struct ccb_hdr_0x17 *)addr;
75 		if (hdr17->flags & CAM_SG_LIST_PHYS_0x16) {
76 			hdr17->flags &= ~CAM_SG_LIST_PHYS_0x16;
77 			hdr17->flags |= CAM_DATA_SG_PADDR;
78 		}
79 		if (hdr17->flags & CAM_DATA_PHYS_0x16) {
80 			hdr17->flags &= ~CAM_DATA_PHYS_0x16;
81 			hdr17->flags |= CAM_DATA_PADDR;
82 		}
83 		if (hdr17->flags & CAM_SCATTER_VALID_0x16) {
84 			hdr17->flags &= CAM_SCATTER_VALID_0x16;
85 			hdr17->flags |= CAM_DATA_SG;
86 		}
87 		cmd = CAMIOCOMMAND;
88 		error = cam_compat_handle_0x17(dev, cmd, addr, flag, td, cbfnp);
89 		break;
90 	}
91 	case CAMGETPASSTHRU_0x16:
92 		cmd = CAMGETPASSTHRU;
93 		error = cam_compat_handle_0x17(dev, cmd, addr, flag, td, cbfnp);
94 		break;
95 	case CAMIOCOMMAND_0x17:
96 		cmd = CAMIOCOMMAND;
97 		error = cam_compat_handle_0x17(dev, cmd, addr, flag, td, cbfnp);
98 		break;
99 	case CAMGETPASSTHRU_0x17:
100 		cmd = CAMGETPASSTHRU;
101 		error = cam_compat_handle_0x17(dev, cmd, addr, flag, td, cbfnp);
102 		break;
103 	case CAMIOCOMMAND_0x18:
104 		cmd = CAMIOCOMMAND;
105 		error = cam_compat_handle_0x18(dev, cmd, addr, flag, td, cbfnp);
106 		break;
107 	case CAMGETPASSTHRU_0x18:
108 		cmd = CAMGETPASSTHRU;
109 		error = cam_compat_handle_0x18(dev, cmd, addr, flag, td, cbfnp);
110 		break;
111 	default:
112 		error = ENOTTY;
113 	}
114 
115 	return (error);
116 }
117 
118 static int
119 cam_compat_handle_0x17(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
120     struct thread *td, d_ioctl_t *cbfnp)
121 {
122 	union ccb		*ccb;
123 	struct ccb_hdr		*hdr;
124 	struct ccb_hdr_0x17	*hdr17;
125 	uint8_t			*ccbb, *ccbb17;
126 	u_int			error;
127 
128 	hdr17 = (struct ccb_hdr_0x17 *)addr;
129 	ccb = xpt_alloc_ccb();
130 	hdr = &ccb->ccb_h;
131 
132 	hdr->pinfo = hdr17->pinfo;
133 	hdr->xpt_links = hdr17->xpt_links;
134 	hdr->sim_links = hdr17->sim_links;
135 	hdr->periph_links = hdr17->periph_links;
136 	hdr->retry_count = hdr17->retry_count;
137 	hdr->cbfcnp = hdr17->cbfcnp;
138 	hdr->func_code = hdr17->func_code;
139 	hdr->status = hdr17->status;
140 	hdr->path = hdr17->path;
141 	hdr->path_id = hdr17->path_id;
142 	hdr->target_id = hdr17->target_id;
143 	hdr->target_lun = hdr17->target_lun;
144 	hdr->flags = hdr17->flags;
145 	hdr->xflags = 0;
146 	hdr->periph_priv = hdr17->periph_priv;
147 	hdr->sim_priv = hdr17->sim_priv;
148 	hdr->timeout = hdr17->timeout;
149 	hdr->softtimeout.tv_sec = 0;
150 	hdr->softtimeout.tv_usec = 0;
151 
152 	ccbb = (uint8_t *)&hdr[1];
153 	ccbb17 = (uint8_t *)&hdr17[1];
154 	if (ccb->ccb_h.func_code == XPT_SET_TRAN_SETTINGS) {
155 		struct ccb_trans_settings *cts;
156 		struct ccb_trans_settings_0x17 *cts17;
157 
158 		cts = &ccb->cts;
159 		cts17 = (struct ccb_trans_settings_0x17 *)hdr17;
160 		cts->type = cts17->type;
161 		cts->protocol = cts17->protocol;
162 		cts->protocol_version = cts17->protocol_version;
163 		cts->transport = cts17->transport;
164 		cts->transport_version = cts17->transport_version;
165 		bcopy(&cts17->proto_specific, &cts->proto_specific,
166 		    sizeof(cts17->proto_specific));
167 		bcopy(&cts17->xport_specific, &cts->xport_specific,
168 		    sizeof(cts17->xport_specific));
169 	} else {
170 		bcopy(ccbb17, ccbb, CAM_0X17_DATA_LEN);
171 	}
172 
173 	error = (cbfnp)(dev, cmd, (caddr_t)ccb, flag, td);
174 
175 	hdr17->pinfo = hdr->pinfo;
176 	hdr17->xpt_links = hdr->xpt_links;
177 	hdr17->sim_links = hdr->sim_links;
178 	hdr17->periph_links = hdr->periph_links;
179 	hdr17->retry_count = hdr->retry_count;
180 	hdr17->cbfcnp = hdr->cbfcnp;
181 	hdr17->func_code = hdr->func_code;
182 	hdr17->status = hdr->status;
183 	hdr17->path = hdr->path;
184 	hdr17->path_id = hdr->path_id;
185 	hdr17->target_id = hdr->target_id;
186 	hdr17->target_lun = hdr->target_lun;
187 	hdr17->flags = hdr->flags;
188 	hdr17->periph_priv = hdr->periph_priv;
189 	hdr17->sim_priv = hdr->sim_priv;
190 	hdr17->timeout = hdr->timeout;
191 
192 	if (ccb->ccb_h.func_code == XPT_PATH_INQ) {
193 		struct ccb_pathinq	*cpi;
194 		struct ccb_pathinq_0x17 *cpi17;
195 
196 		/* The PATH_INQ only needs special handling on the way out */
197 		cpi = &ccb->cpi;
198 		cpi17 = (struct ccb_pathinq_0x17 *)hdr17;
199 		cpi17->version_num = cpi->version_num;
200 		cpi17->hba_inquiry = cpi->hba_inquiry;
201 		cpi17->target_sprt = (u_int8_t)cpi->target_sprt;
202 		cpi17->hba_misc = (u_int8_t)cpi->hba_misc;
203 		cpi17->hba_eng_cnt = cpi->hba_eng_cnt;
204 		bcopy(&cpi->vuhba_flags[0], &cpi17->vuhba_flags[0], VUHBALEN);
205 		cpi17->max_target = cpi->max_target;
206 		cpi17->max_lun = cpi->max_lun;
207 		cpi17->async_flags = cpi->async_flags;
208 		cpi17->hpath_id = cpi->hpath_id;
209 		cpi17->initiator_id = cpi->initiator_id;
210 		bcopy(&cpi->sim_vid[0], &cpi17->sim_vid[0], SIM_IDLEN);
211 		bcopy(&cpi->hba_vid[0], &cpi17->hba_vid[0], HBA_IDLEN);
212 		bcopy(&cpi->dev_name[0], &cpi17->dev_name[0], DEV_IDLEN);
213 		cpi17->unit_number = cpi->unit_number;
214 		cpi17->bus_id = cpi->bus_id;
215 		cpi17->base_transfer_speed = cpi->base_transfer_speed;
216 		cpi17->protocol = cpi->protocol;
217 		cpi17->protocol_version = cpi->protocol_version;
218 		cpi17->transport = cpi->transport;
219 		cpi17->transport_version = cpi->transport_version;
220 		bcopy(&cpi->xport_specific, &cpi17->xport_specific,
221 		    PATHINQ_SETTINGS_SIZE);
222 		cpi17->maxio = cpi->maxio;
223 		cpi17->hba_vendor = cpi->hba_vendor;
224 		cpi17->hba_device = cpi->hba_device;
225 		cpi17->hba_subvendor = cpi->hba_subvendor;
226 		cpi17->hba_subdevice = cpi->hba_subdevice;
227 	} else if (ccb->ccb_h.func_code == XPT_GET_TRAN_SETTINGS) {
228 		struct ccb_trans_settings *cts;
229 		struct ccb_trans_settings_0x17 *cts17;
230 
231 		cts = &ccb->cts;
232 		cts17 = (struct ccb_trans_settings_0x17 *)hdr17;
233 		cts17->type = cts->type;
234 		cts17->protocol = cts->protocol;
235 		cts17->protocol_version = cts->protocol_version;
236 		cts17->transport = cts->transport;
237 		cts17->transport_version = cts->transport_version;
238 		bcopy(&cts->proto_specific, &cts17->proto_specific,
239 		    sizeof(cts17->proto_specific));
240 		bcopy(&cts->xport_specific, &cts17->xport_specific,
241 		    sizeof(cts17->xport_specific));
242 	} else if (ccb->ccb_h.func_code == XPT_DEV_MATCH) {
243 		/* Copy the rest of the header over */
244 		bcopy(ccbb, ccbb17, CAM_0X17_DATA_LEN);
245 
246 		cam_compat_translate_dev_match_0x18(ccb);
247 	} else {
248 		bcopy(ccbb, ccbb17, CAM_0X17_DATA_LEN);
249 	}
250 
251 	xpt_free_ccb(ccb);
252 
253 	return (error);
254 }
255 
256 static int
257 cam_compat_handle_0x18(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
258     struct thread *td, d_ioctl_t *cbfnp)
259 {
260 	union ccb		*ccb;
261 	struct ccb_hdr		*hdr;
262 	struct ccb_hdr_0x18	*hdr18;
263 	uint8_t			*ccbb, *ccbb18;
264 	u_int			error;
265 
266 	hdr18 = (struct ccb_hdr_0x18 *)addr;
267 	ccb = xpt_alloc_ccb();
268 	hdr = &ccb->ccb_h;
269 
270 	hdr->pinfo = hdr18->pinfo;
271 	hdr->xpt_links = hdr18->xpt_links;
272 	hdr->sim_links = hdr18->sim_links;
273 	hdr->periph_links = hdr18->periph_links;
274 	hdr->retry_count = hdr18->retry_count;
275 	hdr->cbfcnp = hdr18->cbfcnp;
276 	hdr->func_code = hdr18->func_code;
277 	hdr->status = hdr18->status;
278 	hdr->path = hdr18->path;
279 	hdr->path_id = hdr18->path_id;
280 	hdr->target_id = hdr18->target_id;
281 	hdr->target_lun = hdr18->target_lun;
282 	if (hdr18->xflags & CAM_EXTLUN_VALID_0x18)
283 		hdr->target_lun = hdr18->ext_lun;
284 	hdr->flags = hdr18->flags;
285 	hdr->xflags = hdr18->xflags;
286 	hdr->periph_priv = hdr18->periph_priv;
287 	hdr->sim_priv = hdr18->sim_priv;
288 	hdr->timeout = hdr18->timeout;
289 	hdr->softtimeout.tv_sec = 0;
290 	hdr->softtimeout.tv_usec = 0;
291 
292 	ccbb = (uint8_t *)&hdr[1];
293 	ccbb18 = (uint8_t *)&hdr18[1];
294 	if (ccb->ccb_h.func_code == XPT_SET_TRAN_SETTINGS) {
295 		struct ccb_trans_settings *cts;
296 		struct ccb_trans_settings_0x18 *cts18;
297 
298 		cts = &ccb->cts;
299 		cts18 = (struct ccb_trans_settings_0x18 *)hdr18;
300 		cts->type = cts18->type;
301 		cts->protocol = cts18->protocol;
302 		cts->protocol_version = cts18->protocol_version;
303 		cts->transport = cts18->transport;
304 		cts->transport_version = cts18->transport_version;
305 		bcopy(&cts18->proto_specific, &cts->proto_specific,
306 		    sizeof(cts18->proto_specific));
307 		bcopy(&cts18->xport_specific, &cts->xport_specific,
308 		    sizeof(cts18->xport_specific));
309 	} else {
310 		bcopy(ccbb18, ccbb, CAM_0X18_DATA_LEN);
311 	}
312 
313 	error = (cbfnp)(dev, cmd, (caddr_t)ccb, flag, td);
314 
315 	hdr18->pinfo = hdr->pinfo;
316 	hdr18->xpt_links = hdr->xpt_links;
317 	hdr18->sim_links = hdr->sim_links;
318 	hdr18->periph_links = hdr->periph_links;
319 	hdr18->retry_count = hdr->retry_count;
320 	hdr18->cbfcnp = hdr->cbfcnp;
321 	hdr18->func_code = hdr->func_code;
322 	hdr18->status = hdr->status;
323 	hdr18->path = hdr->path;
324 	hdr18->path_id = hdr->path_id;
325 	hdr18->target_id = hdr->target_id;
326 	hdr18->target_lun = hdr->target_lun;
327 	hdr18->ext_lun = hdr->target_lun;
328 	hdr18->flags = hdr->flags;
329 	hdr18->xflags = hdr->xflags | CAM_EXTLUN_VALID_0x18;
330 	hdr18->periph_priv = hdr->periph_priv;
331 	hdr18->sim_priv = hdr->sim_priv;
332 	hdr18->timeout = hdr->timeout;
333 
334 	if (ccb->ccb_h.func_code == XPT_GET_TRAN_SETTINGS) {
335 		struct ccb_trans_settings *cts;
336 		struct ccb_trans_settings_0x18 *cts18;
337 
338 		cts = &ccb->cts;
339 		cts18 = (struct ccb_trans_settings_0x18 *)hdr18;
340 		cts18->type = cts->type;
341 		cts18->protocol = cts->protocol;
342 		cts18->protocol_version = cts->protocol_version;
343 		cts18->transport = cts->transport;
344 		cts18->transport_version = cts->transport_version;
345 		bcopy(&cts->proto_specific, &cts18->proto_specific,
346 		    sizeof(cts18->proto_specific));
347 		bcopy(&cts->xport_specific, &cts18->xport_specific,
348 		    sizeof(cts18->xport_specific));
349 	} else if (ccb->ccb_h.func_code == XPT_DEV_MATCH) {
350 		bcopy(ccbb, ccbb18, CAM_0X18_DATA_LEN);
351 		cam_compat_translate_dev_match_0x18(ccb);
352 	} else {
353 		bcopy(ccbb, ccbb18, CAM_0X18_DATA_LEN);
354 	}
355 
356 	xpt_free_ccb(ccb);
357 
358 	return (error);
359 }
360 
361 static int
362 cam_compat_translate_dev_match_0x18(union ccb *ccb)
363 {
364 	struct dev_match_result		*dm;
365 	struct dev_match_result_0x18	*dm18;
366 	struct cam_periph_map_info	mapinfo;
367 	int i;
368 
369 	/* Remap the CCB into kernel address space */
370 	bzero(&mapinfo, sizeof(mapinfo));
371 	cam_periph_mapmem(ccb, &mapinfo, MAXPHYS);
372 
373 	dm = ccb->cdm.matches;
374 	/* Translate in-place: old fields are smaller */
375 	dm18 = (struct dev_match_result_0x18 *)(dm);
376 
377 	for (i = 0; i < ccb->cdm.num_matches; i++) {
378 		dm18[i].type = dm[i].type;
379 		switch (dm[i].type) {
380 		case DEV_MATCH_PERIPH:
381 			memcpy(&dm18[i].result.periph_result.periph_name,
382 			    &dm[i].result.periph_result.periph_name,
383 			    DEV_IDLEN);
384 			dm18[i].result.periph_result.unit_number =
385 			   dm[i].result.periph_result.unit_number;
386 			dm18[i].result.periph_result.path_id =
387 			   dm[i].result.periph_result.path_id;
388 			dm18[i].result.periph_result.target_id =
389 			   dm[i].result.periph_result.target_id;
390 			dm18[i].result.periph_result.target_lun =
391 			   dm[i].result.periph_result.target_lun;
392 			break;
393 		case DEV_MATCH_DEVICE:
394 			dm18[i].result.device_result.path_id =
395 			   dm[i].result.device_result.path_id;
396 			dm18[i].result.device_result.target_id =
397 			   dm[i].result.device_result.target_id;
398 			dm18[i].result.device_result.target_lun =
399 			   dm[i].result.device_result.target_lun;
400 			dm18[i].result.device_result.protocol =
401 			   dm[i].result.device_result.protocol;
402 			memcpy(&dm18[i].result.device_result.inq_data,
403 			    &dm[i].result.device_result.inq_data,
404 			    sizeof(struct scsi_inquiry_data));
405 			memcpy(&dm18[i].result.device_result.ident_data,
406 			    &dm[i].result.device_result.ident_data,
407 			    sizeof(struct ata_params));
408 			dm18[i].result.device_result.flags =
409 			   dm[i].result.device_result.flags;
410 			break;
411 		case DEV_MATCH_BUS:
412 			memcpy(&dm18[i].result.bus_result,
413 			    &dm[i].result.bus_result,
414 			    sizeof(struct bus_match_result));
415 			break;
416 		}
417 	}
418 
419 	cam_periph_unmapmem(ccb, &mapinfo);
420 
421 	return (0);
422 }
423