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_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 = (u_int8_t)cpi->target_sprt; 220 cpi17->hba_misc = (u_int8_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