xref: /freebsd/sys/cam/cam_compat.c (revision 7ef62cebc2f965b0f640263e179276928885e33d)
1 /*-
2  * CAM ioctl compatibility shims
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
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_handle_0x19(struct cdev *dev, u_long cmd, caddr_t addr,
62     int flag, struct thread *td, d_ioctl_t *cbfnp);
63 static int cam_compat_translate_dev_match_0x18(union ccb *ccb);
64 
65 int
66 cam_compat_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
67     struct thread *td, d_ioctl_t *cbfnp)
68 {
69 	int error;
70 
71 	switch (cmd) {
72 	case CAMIOCOMMAND_0x16:
73 	{
74 		struct ccb_hdr_0x17 *hdr17;
75 
76 		hdr17 = (struct ccb_hdr_0x17 *)addr;
77 		if (hdr17->flags & CAM_SG_LIST_PHYS_0x16) {
78 			hdr17->flags &= ~CAM_SG_LIST_PHYS_0x16;
79 			hdr17->flags |= CAM_DATA_SG_PADDR;
80 		}
81 		if (hdr17->flags & CAM_DATA_PHYS_0x16) {
82 			hdr17->flags &= ~CAM_DATA_PHYS_0x16;
83 			hdr17->flags |= CAM_DATA_PADDR;
84 		}
85 		if (hdr17->flags & CAM_SCATTER_VALID_0x16) {
86 			hdr17->flags &= CAM_SCATTER_VALID_0x16;
87 			hdr17->flags |= CAM_DATA_SG;
88 		}
89 		cmd = CAMIOCOMMAND;
90 		error = cam_compat_handle_0x17(dev, cmd, addr, flag, td, cbfnp);
91 		break;
92 	}
93 	case CAMGETPASSTHRU_0x16:
94 		cmd = CAMGETPASSTHRU;
95 		error = cam_compat_handle_0x17(dev, cmd, addr, flag, td, cbfnp);
96 		break;
97 	case CAMIOCOMMAND_0x17:
98 		cmd = CAMIOCOMMAND;
99 		error = cam_compat_handle_0x17(dev, cmd, addr, flag, td, cbfnp);
100 		break;
101 	case CAMGETPASSTHRU_0x17:
102 		cmd = CAMGETPASSTHRU;
103 		error = cam_compat_handle_0x17(dev, cmd, addr, flag, td, cbfnp);
104 		break;
105 	case CAMIOCOMMAND_0x18:
106 		cmd = CAMIOCOMMAND;
107 		error = cam_compat_handle_0x18(dev, cmd, addr, flag, td, cbfnp);
108 		break;
109 	case CAMGETPASSTHRU_0x18:
110 		cmd = CAMGETPASSTHRU;
111 		error = cam_compat_handle_0x18(dev, cmd, addr, flag, td, cbfnp);
112 		break;
113 	case CAMIOCOMMAND_0x19:
114 		cmd = CAMIOCOMMAND;
115 		error = cam_compat_handle_0x19(dev, cmd, addr, flag, td, cbfnp);
116 		break;
117 	case CAMGETPASSTHRU_0x19:
118 		cmd = CAMGETPASSTHRU;
119 		error = cam_compat_handle_0x19(dev, cmd, addr, flag, td, cbfnp);
120 		break;
121 	case CAMIOQUEUE_0x19:
122 		cmd = CAMIOQUEUE;
123 		error = cam_compat_handle_0x19(dev, cmd, addr, flag, td, cbfnp);
124 		break;
125 	case CAMIOGET_0x19:
126 		cmd = CAMIOGET;
127 		error = cam_compat_handle_0x19(dev, cmd, addr, flag, td, cbfnp);
128 		break;
129 	default:
130 		error = ENOTTY;
131 	}
132 
133 	return (error);
134 }
135 
136 static int
137 cam_compat_handle_0x17(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
138     struct thread *td, d_ioctl_t *cbfnp)
139 {
140 	union ccb		*ccb;
141 	struct ccb_hdr		*hdr;
142 	struct ccb_hdr_0x17	*hdr17;
143 	uint8_t			*ccbb, *ccbb17;
144 	u_int			error;
145 
146 	hdr17 = (struct ccb_hdr_0x17 *)addr;
147 	ccb = xpt_alloc_ccb();
148 	hdr = &ccb->ccb_h;
149 
150 	hdr->pinfo = hdr17->pinfo;
151 	hdr->xpt_links = hdr17->xpt_links;
152 	hdr->sim_links = hdr17->sim_links;
153 	hdr->periph_links = hdr17->periph_links;
154 	hdr->retry_count = hdr17->retry_count;
155 	hdr->cbfcnp = hdr17->cbfcnp;
156 	hdr->func_code = hdr17->func_code;
157 	hdr->status = hdr17->status;
158 	hdr->path = hdr17->path;
159 	hdr->path_id = hdr17->path_id;
160 	hdr->target_id = hdr17->target_id;
161 	hdr->target_lun = hdr17->target_lun;
162 	hdr->flags = hdr17->flags;
163 	hdr->xflags = 0;
164 	hdr->periph_priv = hdr17->periph_priv;
165 	hdr->sim_priv = hdr17->sim_priv;
166 	hdr->timeout = hdr17->timeout;
167 	hdr->softtimeout.tv_sec = 0;
168 	hdr->softtimeout.tv_usec = 0;
169 
170 	ccbb = (uint8_t *)&hdr[1];
171 	ccbb17 = (uint8_t *)&hdr17[1];
172 	if (ccb->ccb_h.func_code == XPT_SET_TRAN_SETTINGS) {
173 		struct ccb_trans_settings *cts;
174 		struct ccb_trans_settings_0x17 *cts17;
175 
176 		cts = &ccb->cts;
177 		cts17 = (struct ccb_trans_settings_0x17 *)hdr17;
178 		cts->type = cts17->type;
179 		cts->protocol = cts17->protocol;
180 		cts->protocol_version = cts17->protocol_version;
181 		cts->transport = cts17->transport;
182 		cts->transport_version = cts17->transport_version;
183 		bcopy(&cts17->proto_specific, &cts->proto_specific,
184 		    sizeof(cts17->proto_specific));
185 		bcopy(&cts17->xport_specific, &cts->xport_specific,
186 		    sizeof(cts17->xport_specific));
187 	} else {
188 		bcopy(ccbb17, ccbb, CAM_0X17_DATA_LEN);
189 	}
190 
191 	error = cam_compat_handle_0x19(dev, cmd, (caddr_t)ccb, flag, td, cbfnp);
192 
193 	hdr17->pinfo = hdr->pinfo;
194 	hdr17->xpt_links = hdr->xpt_links;
195 	hdr17->sim_links = hdr->sim_links;
196 	hdr17->periph_links = hdr->periph_links;
197 	hdr17->retry_count = hdr->retry_count;
198 	hdr17->cbfcnp = hdr->cbfcnp;
199 	hdr17->func_code = hdr->func_code;
200 	hdr17->status = hdr->status;
201 	hdr17->path = hdr->path;
202 	hdr17->path_id = hdr->path_id;
203 	hdr17->target_id = hdr->target_id;
204 	hdr17->target_lun = hdr->target_lun;
205 	hdr17->flags = hdr->flags;
206 	hdr17->periph_priv = hdr->periph_priv;
207 	hdr17->sim_priv = hdr->sim_priv;
208 	hdr17->timeout = hdr->timeout;
209 
210 	if (ccb->ccb_h.func_code == XPT_PATH_INQ) {
211 		struct ccb_pathinq	*cpi;
212 		struct ccb_pathinq_0x17 *cpi17;
213 
214 		/* The PATH_INQ only needs special handling on the way out */
215 		cpi = &ccb->cpi;
216 		cpi17 = (struct ccb_pathinq_0x17 *)hdr17;
217 		cpi17->version_num = cpi->version_num;
218 		cpi17->hba_inquiry = cpi->hba_inquiry;
219 		cpi17->target_sprt = (uint8_t)cpi->target_sprt;
220 		cpi17->hba_misc = (uint8_t)cpi->hba_misc;
221 		cpi17->hba_eng_cnt = cpi->hba_eng_cnt;
222 		bcopy(&cpi->vuhba_flags[0], &cpi17->vuhba_flags[0], VUHBALEN);
223 		cpi17->max_target = cpi->max_target;
224 		cpi17->max_lun = cpi->max_lun;
225 		cpi17->async_flags = cpi->async_flags;
226 		cpi17->hpath_id = cpi->hpath_id;
227 		cpi17->initiator_id = cpi->initiator_id;
228 		bcopy(&cpi->sim_vid[0], &cpi17->sim_vid[0], SIM_IDLEN);
229 		bcopy(&cpi->hba_vid[0], &cpi17->hba_vid[0], HBA_IDLEN);
230 		bcopy(&cpi->dev_name[0], &cpi17->dev_name[0], DEV_IDLEN);
231 		cpi17->unit_number = cpi->unit_number;
232 		cpi17->bus_id = cpi->bus_id;
233 		cpi17->base_transfer_speed = cpi->base_transfer_speed;
234 		cpi17->protocol = cpi->protocol;
235 		cpi17->protocol_version = cpi->protocol_version;
236 		cpi17->transport = cpi->transport;
237 		cpi17->transport_version = cpi->transport_version;
238 		bcopy(&cpi->xport_specific, &cpi17->xport_specific,
239 		    PATHINQ_SETTINGS_SIZE);
240 		cpi17->maxio = cpi->maxio;
241 		cpi17->hba_vendor = cpi->hba_vendor;
242 		cpi17->hba_device = cpi->hba_device;
243 		cpi17->hba_subvendor = cpi->hba_subvendor;
244 		cpi17->hba_subdevice = cpi->hba_subdevice;
245 	} else if (ccb->ccb_h.func_code == XPT_GET_TRAN_SETTINGS) {
246 		struct ccb_trans_settings *cts;
247 		struct ccb_trans_settings_0x17 *cts17;
248 
249 		cts = &ccb->cts;
250 		cts17 = (struct ccb_trans_settings_0x17 *)hdr17;
251 		cts17->type = cts->type;
252 		cts17->protocol = cts->protocol;
253 		cts17->protocol_version = cts->protocol_version;
254 		cts17->transport = cts->transport;
255 		cts17->transport_version = cts->transport_version;
256 		bcopy(&cts->proto_specific, &cts17->proto_specific,
257 		    sizeof(cts17->proto_specific));
258 		bcopy(&cts->xport_specific, &cts17->xport_specific,
259 		    sizeof(cts17->xport_specific));
260 	} else if (ccb->ccb_h.func_code == XPT_DEV_MATCH) {
261 		/* Copy the rest of the header over */
262 		bcopy(ccbb, ccbb17, CAM_0X17_DATA_LEN);
263 
264 		cam_compat_translate_dev_match_0x18(ccb);
265 	} else {
266 		bcopy(ccbb, ccbb17, CAM_0X17_DATA_LEN);
267 	}
268 
269 	xpt_free_ccb(ccb);
270 
271 	return (error);
272 }
273 
274 static int
275 cam_compat_handle_0x18(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
276     struct thread *td, d_ioctl_t *cbfnp)
277 {
278 	union ccb		*ccb;
279 	struct ccb_hdr		*hdr;
280 	struct ccb_hdr_0x18	*hdr18;
281 	uint8_t			*ccbb, *ccbb18;
282 	u_int			error;
283 
284 	hdr18 = (struct ccb_hdr_0x18 *)addr;
285 	ccb = xpt_alloc_ccb();
286 	hdr = &ccb->ccb_h;
287 
288 	hdr->pinfo = hdr18->pinfo;
289 	hdr->xpt_links = hdr18->xpt_links;
290 	hdr->sim_links = hdr18->sim_links;
291 	hdr->periph_links = hdr18->periph_links;
292 	hdr->retry_count = hdr18->retry_count;
293 	hdr->cbfcnp = hdr18->cbfcnp;
294 	hdr->func_code = hdr18->func_code;
295 	hdr->status = hdr18->status;
296 	hdr->path = hdr18->path;
297 	hdr->path_id = hdr18->path_id;
298 	hdr->target_id = hdr18->target_id;
299 	hdr->target_lun = hdr18->target_lun;
300 	if (hdr18->xflags & CAM_EXTLUN_VALID_0x18)
301 		hdr->target_lun = hdr18->ext_lun;
302 	hdr->flags = hdr18->flags;
303 	hdr->xflags = hdr18->xflags;
304 	hdr->periph_priv = hdr18->periph_priv;
305 	hdr->sim_priv = hdr18->sim_priv;
306 	hdr->timeout = hdr18->timeout;
307 	hdr->softtimeout.tv_sec = 0;
308 	hdr->softtimeout.tv_usec = 0;
309 
310 	ccbb = (uint8_t *)&hdr[1];
311 	ccbb18 = (uint8_t *)&hdr18[1];
312 	if (ccb->ccb_h.func_code == XPT_SET_TRAN_SETTINGS) {
313 		struct ccb_trans_settings *cts;
314 		struct ccb_trans_settings_0x18 *cts18;
315 
316 		cts = &ccb->cts;
317 		cts18 = (struct ccb_trans_settings_0x18 *)hdr18;
318 		cts->type = cts18->type;
319 		cts->protocol = cts18->protocol;
320 		cts->protocol_version = cts18->protocol_version;
321 		cts->transport = cts18->transport;
322 		cts->transport_version = cts18->transport_version;
323 		bcopy(&cts18->proto_specific, &cts->proto_specific,
324 		    sizeof(cts18->proto_specific));
325 		bcopy(&cts18->xport_specific, &cts->xport_specific,
326 		    sizeof(cts18->xport_specific));
327 	} else {
328 		bcopy(ccbb18, ccbb, CAM_0X18_DATA_LEN);
329 	}
330 
331 	error = cam_compat_handle_0x19(dev, cmd, (caddr_t)ccb, flag, td, cbfnp);
332 
333 	hdr18->pinfo = hdr->pinfo;
334 	hdr18->xpt_links = hdr->xpt_links;
335 	hdr18->sim_links = hdr->sim_links;
336 	hdr18->periph_links = hdr->periph_links;
337 	hdr18->retry_count = hdr->retry_count;
338 	hdr18->cbfcnp = hdr->cbfcnp;
339 	hdr18->func_code = hdr->func_code;
340 	hdr18->status = hdr->status;
341 	hdr18->path = hdr->path;
342 	hdr18->path_id = hdr->path_id;
343 	hdr18->target_id = hdr->target_id;
344 	hdr18->target_lun = hdr->target_lun;
345 	hdr18->ext_lun = hdr->target_lun;
346 	hdr18->flags = hdr->flags;
347 	hdr18->xflags = hdr->xflags | CAM_EXTLUN_VALID_0x18;
348 	hdr18->periph_priv = hdr->periph_priv;
349 	hdr18->sim_priv = hdr->sim_priv;
350 	hdr18->timeout = hdr->timeout;
351 
352 	if (ccb->ccb_h.func_code == XPT_GET_TRAN_SETTINGS) {
353 		struct ccb_trans_settings *cts;
354 		struct ccb_trans_settings_0x18 *cts18;
355 
356 		cts = &ccb->cts;
357 		cts18 = (struct ccb_trans_settings_0x18 *)hdr18;
358 		cts18->type = cts->type;
359 		cts18->protocol = cts->protocol;
360 		cts18->protocol_version = cts->protocol_version;
361 		cts18->transport = cts->transport;
362 		cts18->transport_version = cts->transport_version;
363 		bcopy(&cts->proto_specific, &cts18->proto_specific,
364 		    sizeof(cts18->proto_specific));
365 		bcopy(&cts->xport_specific, &cts18->xport_specific,
366 		    sizeof(cts18->xport_specific));
367 	} else if (ccb->ccb_h.func_code == XPT_DEV_MATCH) {
368 		bcopy(ccbb, ccbb18, CAM_0X18_DATA_LEN);
369 		cam_compat_translate_dev_match_0x18(ccb);
370 	} else {
371 		bcopy(ccbb, ccbb18, CAM_0X18_DATA_LEN);
372 	}
373 
374 	xpt_free_ccb(ccb);
375 
376 	return (error);
377 }
378 
379 static int
380 cam_compat_translate_dev_match_0x18(union ccb *ccb)
381 {
382 	struct dev_match_result		*dm;
383 	struct dev_match_result_0x18	*dm18;
384 	struct cam_periph_map_info	mapinfo;
385 	int i;
386 
387 	/* Remap the CCB into kernel address space */
388 	bzero(&mapinfo, sizeof(mapinfo));
389 	cam_periph_mapmem(ccb, &mapinfo, maxphys);
390 
391 	dm = ccb->cdm.matches;
392 	/* Translate in-place: old fields are smaller */
393 	dm18 = (struct dev_match_result_0x18 *)(dm);
394 
395 	for (i = 0; i < ccb->cdm.num_matches; i++) {
396 		dm18[i].type = dm[i].type;
397 		switch (dm[i].type) {
398 		case DEV_MATCH_PERIPH:
399 			memcpy(&dm18[i].result.periph_result.periph_name,
400 			    &dm[i].result.periph_result.periph_name,
401 			    DEV_IDLEN);
402 			dm18[i].result.periph_result.unit_number =
403 			   dm[i].result.periph_result.unit_number;
404 			dm18[i].result.periph_result.path_id =
405 			   dm[i].result.periph_result.path_id;
406 			dm18[i].result.periph_result.target_id =
407 			   dm[i].result.periph_result.target_id;
408 			dm18[i].result.periph_result.target_lun =
409 			   dm[i].result.periph_result.target_lun;
410 			break;
411 		case DEV_MATCH_DEVICE:
412 			dm18[i].result.device_result.path_id =
413 			   dm[i].result.device_result.path_id;
414 			dm18[i].result.device_result.target_id =
415 			   dm[i].result.device_result.target_id;
416 			dm18[i].result.device_result.target_lun =
417 			   dm[i].result.device_result.target_lun;
418 			dm18[i].result.device_result.protocol =
419 			   dm[i].result.device_result.protocol;
420 			memcpy(&dm18[i].result.device_result.inq_data,
421 			    &dm[i].result.device_result.inq_data,
422 			    sizeof(struct scsi_inquiry_data));
423 			memcpy(&dm18[i].result.device_result.ident_data,
424 			    &dm[i].result.device_result.ident_data,
425 			    sizeof(struct ata_params));
426 			dm18[i].result.device_result.flags =
427 			   dm[i].result.device_result.flags;
428 			break;
429 		case DEV_MATCH_BUS:
430 			memcpy(&dm18[i].result.bus_result,
431 			    &dm[i].result.bus_result,
432 			    sizeof(struct bus_match_result));
433 			break;
434 		}
435 	}
436 
437 	cam_periph_unmapmem(ccb, &mapinfo);
438 
439 	return (0);
440 }
441 
442 static int
443 cam_compat_handle_0x19(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
444     struct thread *td, d_ioctl_t *cbfnp)
445 {
446 	union ccb *ccb = (union ccb *)addr;
447 	struct cam_periph_map_info	mapinfo;
448 
449 	if (cmd == CAMIOCOMMAND && ccb->ccb_h.func_code == XPT_DEV_MATCH) {
450 		bzero(&mapinfo, sizeof(mapinfo));
451 		cam_periph_mapmem(ccb, &mapinfo, maxphys);
452 		for (int i = 0; i < ccb->cdm.num_patterns; i++) {
453 			struct dev_match_pattern *p = &ccb->cdm.patterns[i];
454 
455 			if (p->type == DEV_MATCH_BUS &&
456 			    p->pattern.bus_pattern.flags == 0x00f)
457 				p->pattern.bus_pattern.flags = BUS_MATCH_ANY;
458 			if (p->type == DEV_MATCH_DEVICE &&
459 			    p->pattern.device_pattern.flags == 0x00f)
460 				p->pattern.device_pattern.flags = DEV_MATCH_ANY;
461 			if (p->type == DEV_MATCH_PERIPH &&
462 			    p->pattern.periph_pattern.flags == 0x01f)
463 				p->pattern.periph_pattern.flags = PERIPH_MATCH_ANY;
464 		}
465 		cam_periph_unmapmem(ccb, &mapinfo);
466 	}
467 	return ((cbfnp)(dev, cmd, addr, flag, td));
468 }
469