1 /* $OpenBSD: scsi_ioctl.c,v 1.33 2009/10/12 12:04:11 dlg 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/malloc.h> 46 #include <sys/buf.h> 47 #include <sys/proc.h> 48 #include <sys/device.h> 49 #include <sys/fcntl.h> 50 51 #include <scsi/scsi_all.h> 52 #include <scsi/scsiconf.h> 53 #include <sys/scsiio.h> 54 55 int scsi_ioc_cmd(struct scsi_link *, scsireq_t *); 56 57 const unsigned char scsi_readsafe_cmd[256] = { 58 [0x00] = 1, /* TEST UNIT READY */ 59 [0x03] = 1, /* REQUEST SENSE */ 60 [0x08] = 1, /* READ(6) */ 61 [0x12] = 1, /* INQUIRY */ 62 [0x1a] = 1, /* MODE SENSE */ 63 [0x1b] = 1, /* START STOP */ 64 [0x23] = 1, /* READ FORMAT CAPACITIES */ 65 [0x25] = 1, /* READ CDVD CAPACITY */ 66 [0x28] = 1, /* READ(10) */ 67 [0x2b] = 1, /* SEEK */ 68 [0x2f] = 1, /* VERIFY(10) */ 69 [0x3c] = 1, /* READ BUFFER */ 70 [0x3e] = 1, /* READ LONG */ 71 [0x42] = 1, /* READ SUBCHANNEL */ 72 [0x43] = 1, /* READ TOC PMA ATIP */ 73 [0x44] = 1, /* READ HEADER */ 74 [0x45] = 1, /* PLAY AUDIO(10) */ 75 [0x46] = 1, /* GET CONFIGURATION */ 76 [0x47] = 1, /* PLAY AUDIO MSF */ 77 [0x48] = 1, /* PLAY AUDIO TI */ 78 [0x4a] = 1, /* GET EVENT STATUS NOTIFICATION */ 79 [0x4b] = 1, /* PAUSE RESUME */ 80 [0x4e] = 1, /* STOP PLAY SCAN */ 81 [0x51] = 1, /* READ DISC INFO */ 82 [0x52] = 1, /* READ TRACK RZONE INFO */ 83 [0x5a] = 1, /* MODE SENSE(10) */ 84 [0x88] = 1, /* READ(16) */ 85 [0x8f] = 1, /* VERIFY(16) */ 86 [0xa4] = 1, /* REPORT KEY */ 87 [0xa5] = 1, /* PLAY AUDIO(12) */ 88 [0xa8] = 1, /* READ(12) */ 89 [0xac] = 1, /* GET PERFORMANCE */ 90 [0xad] = 1, /* READ DVD STRUCTURE */ 91 [0xb9] = 1, /* READ CD MSF */ 92 [0xba] = 1, /* SCAN */ 93 [0xbc] = 1, /* PLAY CD */ 94 [0xbd] = 1, /* MECHANISM STATUS */ 95 [0xbe] = 1 /* READ CD */ 96 }; 97 98 int 99 scsi_ioc_cmd(struct scsi_link *link, scsireq_t *screq) 100 { 101 struct scsi_xfer *xs; 102 int err = 0; 103 int s; 104 105 if (screq->cmdlen > sizeof(struct scsi_generic)) 106 return (EFAULT); 107 108 xs = scsi_xs_get(link, 0); 109 110 memcpy(xs->cmd, screq->cmd, screq->cmdlen); 111 xs->cmdlen = screq->cmdlen; 112 113 if (screq->datalen > 0) { 114 xs->data = malloc(screq->datalen, M_TEMP, M_WAITOK); 115 xs->datalen = screq->datalen; 116 } 117 118 if (screq->flags & SCCMD_READ) 119 xs->flags |= SCSI_DATA_IN; 120 if (screq->flags & SCCMD_WRITE) { 121 if (screq->datalen > 0) { 122 err = copyin(screq->databuf, xs->data, screq->datalen); 123 if (err != 0) 124 goto err; 125 } 126 127 xs->flags |= SCSI_DATA_OUT; 128 } 129 130 xs->timeout = screq->timeout; 131 xs->retries = 0; /* user must do the retries *//* ignored */ 132 133 xs->done = (void (*)(struct scsi_xfer *))wakeup; 134 135 scsi_xs_exec(xs); 136 s = splbio(); 137 while (!ISSET(xs->flags, ITSDONE)) 138 tsleep(xs, PRIBIO, "scsiioc", 0); 139 splx(s); 140 141 screq->retsts = 0; 142 screq->status = xs->status; 143 switch (xs->error) { 144 case XS_NOERROR: 145 /* probably rubbish */ 146 screq->datalen_used = xs->datalen - xs->resid; 147 screq->retsts = SCCMD_OK; 148 break; 149 case XS_SENSE: 150 screq->senselen_used = min(sizeof(xs->sense), 151 sizeof(screq->sense)); 152 bcopy(&xs->sense, screq->sense, screq->senselen_used); 153 screq->retsts = SCCMD_SENSE; 154 break; 155 case XS_SHORTSENSE: 156 printf("XS_SHORTSENSE\n"); 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_UNKNOWN; 161 break; 162 case XS_DRIVER_STUFFUP: 163 screq->retsts = SCCMD_UNKNOWN; 164 break; 165 case XS_TIMEOUT: 166 screq->retsts = SCCMD_TIMEOUT; 167 break; 168 case XS_BUSY: 169 screq->retsts = SCCMD_BUSY; 170 break; 171 default: 172 screq->retsts = SCCMD_UNKNOWN; 173 break; 174 } 175 176 if (screq->datalen > 0 && screq->flags & SCCMD_READ) { 177 err = copyout(xs->data, screq->databuf, screq->datalen); 178 if (err != 0) 179 goto err; 180 } 181 182 err: 183 if (screq->datalen > 0) 184 free(xs->data, M_TEMP); 185 scsi_xs_put(xs); 186 187 return (err); 188 } 189 190 /* 191 * Something (e.g. another driver) has called us 192 * with an sc_link for a target/lun/adapter, and a scsi 193 * specific ioctl to perform, better try. 194 * If user-level type command, we must still be running 195 * in the context of the calling process 196 */ 197 int 198 scsi_do_ioctl(struct scsi_link *sc_link, dev_t dev, u_long cmd, caddr_t addr, 199 int flag, struct proc *p) 200 { 201 SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd)); 202 203 switch(cmd) { 204 case SCIOCIDENTIFY: { 205 struct scsi_addr *sca = (struct scsi_addr *)addr; 206 207 if ((sc_link->flags & (SDEV_ATAPI | SDEV_UMASS)) == 0) 208 /* A 'real' SCSI target. */ 209 sca->type = TYPE_SCSI; 210 else 211 /* An 'emulated' SCSI target. */ 212 sca->type = TYPE_ATAPI; 213 sca->scbus = sc_link->scsibus; 214 sca->target = sc_link->target; 215 sca->lun = sc_link->lun; 216 return (0); 217 } 218 case SCIOCCOMMAND: 219 if (scsi_readsafe_cmd[((scsireq_t *)addr)->cmd[0]]) 220 break; 221 /* FALLTHROUGH */ 222 case SCIOCDEBUG: 223 if ((flag & FWRITE) == 0) 224 return (EPERM); 225 break; 226 default: 227 if (sc_link->adapter->ioctl) 228 return ((sc_link->adapter->ioctl)(sc_link, cmd, addr, 229 flag, p)); 230 else 231 return (ENOTTY); 232 } 233 234 switch(cmd) { 235 case SCIOCCOMMAND: 236 return (scsi_ioc_cmd(sc_link, (scsireq_t *)addr)); 237 case SCIOCDEBUG: { 238 int level = *((int *)addr); 239 240 SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level)); 241 sc_link->flags &= ~SDEV_DBX; /* clear debug bits */ 242 if (level & 1) 243 sc_link->flags |= SDEV_DB1; 244 if (level & 2) 245 sc_link->flags |= SDEV_DB2; 246 if (level & 4) 247 sc_link->flags |= SDEV_DB3; 248 if (level & 8) 249 sc_link->flags |= SDEV_DB4; 250 return (0); 251 } 252 default: 253 #ifdef DIAGNOSTIC 254 panic("scsi_do_ioctl: impossible cmd (%#lx)", cmd); 255 #endif 256 return (0); 257 } 258 } 259