1 /* $OpenBSD: scsi_ioctl.c,v 1.48 2011/06/21 22:36:42 matthew Exp $ */ 2 /* $NetBSD: scsi_ioctl.c,v 1.23 1996/10/12 23:23:17 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1994 Charles Hannum. 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 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Charles Hannum. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Contributed by HD Associates (hd@world.std.com). 35 * Copyright (c) 1992, 1993 HD Associates 36 * 37 * Berkeley style copyright. 38 */ 39 40 #include <sys/types.h> 41 #include <sys/errno.h> 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/file.h> 45 #include <sys/pool.h> 46 #include <sys/buf.h> 47 #include <sys/device.h> 48 #include <sys/fcntl.h> 49 50 #include <scsi/scsi_all.h> 51 #include <scsi/scsiconf.h> 52 53 #include <sys/scsiio.h> 54 #include <sys/ataio.h> 55 56 int scsi_ioc_cmd(struct scsi_link *, scsireq_t *); 57 int scsi_ioc_ata_cmd(struct scsi_link *, atareq_t *); 58 59 const unsigned char scsi_readsafe_cmd[256] = { 60 [0x00] = 1, /* TEST UNIT READY */ 61 [0x03] = 1, /* REQUEST SENSE */ 62 [0x08] = 1, /* READ(6) */ 63 [0x12] = 1, /* INQUIRY */ 64 [0x1a] = 1, /* MODE SENSE */ 65 [0x1b] = 1, /* START STOP */ 66 [0x23] = 1, /* READ FORMAT CAPACITIES */ 67 [0x25] = 1, /* READ CDVD CAPACITY */ 68 [0x28] = 1, /* READ(10) */ 69 [0x2b] = 1, /* SEEK */ 70 [0x2f] = 1, /* VERIFY(10) */ 71 [0x3c] = 1, /* READ BUFFER */ 72 [0x3e] = 1, /* READ LONG */ 73 [0x42] = 1, /* READ SUBCHANNEL */ 74 [0x43] = 1, /* READ TOC PMA ATIP */ 75 [0x44] = 1, /* READ HEADER */ 76 [0x45] = 1, /* PLAY AUDIO(10) */ 77 [0x46] = 1, /* GET CONFIGURATION */ 78 [0x47] = 1, /* PLAY AUDIO MSF */ 79 [0x48] = 1, /* PLAY AUDIO TI */ 80 [0x4a] = 1, /* GET EVENT STATUS NOTIFICATION */ 81 [0x4b] = 1, /* PAUSE RESUME */ 82 [0x4e] = 1, /* STOP PLAY SCAN */ 83 [0x51] = 1, /* READ DISC INFO */ 84 [0x52] = 1, /* READ TRACK RZONE INFO */ 85 [0x5a] = 1, /* MODE SENSE(10) */ 86 [0x88] = 1, /* READ(16) */ 87 [0x8f] = 1, /* VERIFY(16) */ 88 [0xa4] = 1, /* REPORT KEY */ 89 [0xa5] = 1, /* PLAY AUDIO(12) */ 90 [0xa8] = 1, /* READ(12) */ 91 [0xac] = 1, /* GET PERFORMANCE */ 92 [0xad] = 1, /* READ DVD STRUCTURE */ 93 [0xb9] = 1, /* READ CD MSF */ 94 [0xba] = 1, /* SCAN */ 95 [0xbc] = 1, /* PLAY CD */ 96 [0xbd] = 1, /* MECHANISM STATUS */ 97 [0xbe] = 1 /* READ CD */ 98 }; 99 100 int 101 scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq) 102 { 103 struct scsi_xfer *xs; 104 int err = 0; 105 106 if (screq->cmdlen > sizeof(struct scsi_generic)) 107 return (EFAULT); 108 if (screq->datalen > MAXPHYS) 109 return (EINVAL); 110 111 xs = scsi_xs_get(link, 0); 112 if (xs == NULL) 113 return (ENOMEM); 114 115 memcpy(xs->cmd, screq->cmd, screq->cmdlen); 116 xs->cmdlen = screq->cmdlen; 117 118 if (screq->datalen > 0) { 119 xs->data = dma_alloc(screq->datalen, PR_WAITOK | PR_ZERO); 120 if (xs->data == NULL) { 121 err = ENOMEM; 122 goto err; 123 } 124 xs->datalen = screq->datalen; 125 } 126 127 if (screq->flags & SCCMD_READ) 128 xs->flags |= SCSI_DATA_IN; 129 if (screq->flags & SCCMD_WRITE) { 130 if (screq->datalen > 0) { 131 err = copyin(screq->databuf, xs->data, screq->datalen); 132 if (err != 0) 133 goto err; 134 } 135 136 xs->flags |= SCSI_DATA_OUT; 137 } 138 139 xs->flags |= SCSI_SILENT; /* User is responsible for errors. */ 140 xs->timeout = screq->timeout; 141 xs->retries = 0; /* user must do the retries *//* ignored */ 142 143 scsi_xs_sync(xs); 144 145 screq->retsts = 0; 146 screq->status = xs->status; 147 switch (xs->error) { 148 case XS_NOERROR: 149 /* probably rubbish */ 150 screq->datalen_used = xs->datalen - xs->resid; 151 screq->retsts = SCCMD_OK; 152 break; 153 case XS_SENSE: 154 #ifdef SCSIDEBUG 155 scsi_sense_print_debug(xs); 156 #endif 157 screq->senselen_used = min(sizeof(xs->sense), 158 sizeof(screq->sense)); 159 bcopy(&xs->sense, screq->sense, screq->senselen_used); 160 screq->retsts = SCCMD_SENSE; 161 break; 162 case XS_SHORTSENSE: 163 #ifdef SCSIDEBUG 164 scsi_sense_print_debug(xs); 165 #endif 166 printf("XS_SHORTSENSE\n"); 167 screq->senselen_used = min(sizeof(xs->sense), 168 sizeof(screq->sense)); 169 bcopy(&xs->sense, screq->sense, screq->senselen_used); 170 screq->retsts = SCCMD_UNKNOWN; 171 break; 172 case XS_DRIVER_STUFFUP: 173 screq->retsts = SCCMD_UNKNOWN; 174 break; 175 case XS_TIMEOUT: 176 screq->retsts = SCCMD_TIMEOUT; 177 break; 178 case XS_BUSY: 179 screq->retsts = SCCMD_BUSY; 180 break; 181 default: 182 screq->retsts = SCCMD_UNKNOWN; 183 break; 184 } 185 186 if (screq->datalen > 0 && screq->flags & SCCMD_READ) { 187 err = copyout(xs->data, screq->databuf, screq->datalen); 188 if (err != 0) 189 goto err; 190 } 191 192 err: 193 if (xs->data) 194 dma_free(xs->data, screq->datalen); 195 scsi_xs_put(xs); 196 197 return (err); 198 } 199 200 int 201 scsi_ioc_ata_cmd(struct scsi_link *link, atareq_t *atareq) 202 { 203 struct scsi_xfer *xs; 204 struct scsi_ata_passthru_12 *cdb; 205 int err = 0; 206 207 if (atareq->datalen > MAXPHYS) 208 return (EINVAL); 209 210 xs = scsi_xs_get(link, 0); 211 if (xs == NULL) 212 return (ENOMEM); 213 214 cdb = (struct scsi_ata_passthru_12 *)xs->cmd; 215 cdb->opcode = ATA_PASSTHRU_12; 216 217 if (atareq->datalen > 0) { 218 if (atareq->flags & ATACMD_READ) { 219 cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAIN; 220 cdb->flags = ATA_PASSTHRU_T_DIR_READ; 221 } else { 222 cdb->count_proto = ATA_PASSTHRU_PROTO_PIO_DATAOUT; 223 cdb->flags = ATA_PASSTHRU_T_DIR_WRITE; 224 } 225 cdb->flags |= ATA_PASSTHRU_T_LEN_SECTOR_COUNT; 226 } else { 227 cdb->count_proto = ATA_PASSTHRU_PROTO_NON_DATA; 228 cdb->flags = ATA_PASSTHRU_T_LEN_NONE; 229 } 230 cdb->features = atareq->features; 231 cdb->sector_count = atareq->sec_count; 232 cdb->lba_low = atareq->sec_num; 233 cdb->lba_mid = atareq->cylinder; 234 cdb->lba_high = atareq->cylinder >> 8; 235 cdb->device = atareq->head & 0x0f; 236 cdb->command = atareq->command; 237 238 xs->cmdlen = sizeof(*cdb); 239 240 if (atareq->datalen > 0) { 241 xs->data = dma_alloc(atareq->datalen, PR_WAITOK | PR_ZERO); 242 if (xs->data == NULL) { 243 err = ENOMEM; 244 goto err; 245 } 246 xs->datalen = atareq->datalen; 247 } 248 249 if (atareq->flags & ATACMD_READ) 250 xs->flags |= SCSI_DATA_IN; 251 if (atareq->flags & ATACMD_WRITE) { 252 if (atareq->datalen > 0) { 253 err = copyin(atareq->databuf, xs->data, 254 atareq->datalen); 255 if (err != 0) 256 goto err; 257 } 258 259 xs->flags |= SCSI_DATA_OUT; 260 } 261 262 xs->flags |= SCSI_SILENT; /* User is responsible for errors. */ 263 xs->retries = 0; /* user must do the retries *//* ignored */ 264 265 scsi_xs_sync(xs); 266 267 atareq->retsts = ATACMD_ERROR; 268 switch (xs->error) { 269 case XS_SENSE: 270 case XS_SHORTSENSE: 271 #ifdef SCSIDEBUG 272 scsi_sense_print_debug(xs); 273 #endif 274 /* XXX this is not right */ 275 case XS_NOERROR: 276 atareq->retsts = ATACMD_OK; 277 break; 278 default: 279 atareq->retsts = ATACMD_ERROR; 280 break; 281 } 282 283 if (atareq->datalen > 0 && atareq->flags & ATACMD_READ) { 284 err = copyout(xs->data, atareq->databuf, atareq->datalen); 285 if (err != 0) 286 goto err; 287 } 288 289 err: 290 if (xs->data) 291 dma_free(xs->data, atareq->datalen); 292 scsi_xs_put(xs); 293 294 return (err); 295 } 296 297 /* 298 * Something (e.g. another driver) has called us 299 * with an sc_link for a target/lun/adapter, and a scsi 300 * specific ioctl to perform, better try. 301 */ 302 int 303 scsi_do_ioctl(struct scsi_link *sc_link, u_long cmd, caddr_t addr, int flag) 304 { 305 SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd)); 306 307 switch(cmd) { 308 case SCIOCIDENTIFY: { 309 struct scsi_addr *sca = (struct scsi_addr *)addr; 310 311 if ((sc_link->flags & (SDEV_ATAPI | SDEV_UMASS)) == 0) 312 /* A 'real' SCSI target. */ 313 sca->type = TYPE_SCSI; 314 else 315 /* An 'emulated' SCSI target. */ 316 sca->type = TYPE_ATAPI; 317 sca->scbus = sc_link->bus->sc_dev.dv_unit; 318 sca->target = sc_link->target; 319 sca->lun = sc_link->lun; 320 return (0); 321 } 322 case SCIOCCOMMAND: 323 if (scsi_readsafe_cmd[((scsireq_t *)addr)->cmd[0]]) 324 break; 325 /* FALLTHROUGH */ 326 case ATAIOCCOMMAND: 327 case SCIOCDEBUG: 328 if ((flag & FWRITE) == 0) 329 return (EPERM); 330 break; 331 default: 332 if (sc_link->adapter->ioctl) 333 return ((sc_link->adapter->ioctl)(sc_link, cmd, addr, 334 flag)); 335 else 336 return (ENOTTY); 337 } 338 339 switch(cmd) { 340 case SCIOCCOMMAND: 341 return (scsi_ioc_cmd(sc_link, (scsireq_t *)addr)); 342 case ATAIOCCOMMAND: 343 return (scsi_ioc_ata_cmd(sc_link, (atareq_t *)addr)); 344 case SCIOCDEBUG: { 345 int level = *((int *)addr); 346 347 SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level)); 348 sc_link->flags &= ~SDEV_DBX; /* clear debug bits */ 349 if (level & 1) 350 sc_link->flags |= SDEV_DB1; 351 if (level & 2) 352 sc_link->flags |= SDEV_DB2; 353 if (level & 4) 354 sc_link->flags |= SDEV_DB3; 355 if (level & 8) 356 sc_link->flags |= SDEV_DB4; 357 return (0); 358 } 359 default: 360 #ifdef DIAGNOSTIC 361 panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd); 362 #endif 363 return (0); 364 } 365 } 366