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