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