scsi_ioctl.c revision 1.14
1/* $OpenBSD: scsi_ioctl.c,v 1.14 2002/01/07 19:04:46 mickey 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 55struct scsi_ioctl { 56 LIST_ENTRY(scsi_ioctl) si_list; 57 struct buf si_bp; 58 struct uio si_uio; 59 struct iovec si_iov; 60 scsireq_t si_screq; 61 struct scsi_link *si_sc_link; 62}; 63 64LIST_HEAD(, scsi_ioctl) si_head; 65 66struct scsi_ioctl *si_get __P((void)); 67void si_free __P((struct scsi_ioctl *)); 68struct scsi_ioctl *si_find __P((struct buf *)); 69void scsistrategy __P((struct buf *)); 70 71struct scsi_ioctl * 72si_get() 73{ 74 struct scsi_ioctl *si; 75 int s; 76 77 si = malloc(sizeof(struct scsi_ioctl), M_TEMP, M_WAITOK); 78 bzero(si, sizeof(struct scsi_ioctl)); 79 s = splbio(); 80 LIST_INSERT_HEAD(&si_head, si, si_list); 81 splx(s); 82 return (si); 83} 84 85void 86si_free(si) 87 struct scsi_ioctl *si; 88{ 89 int s; 90 91 s = splbio(); 92 LIST_REMOVE(si, si_list); 93 splx(s); 94 free(si, M_TEMP); 95} 96 97struct scsi_ioctl * 98si_find(bp) 99 struct buf *bp; 100{ 101 struct scsi_ioctl *si; 102 int s; 103 104 s = splbio(); 105 for (si = si_head.lh_first; si != 0; si = si->si_list.le_next) 106 if (bp == &si->si_bp) 107 break; 108 splx(s); 109 return (si); 110} 111 112/* 113 * We let the user interpret his own sense in the generic scsi world. 114 * This routine is called at interrupt time if the SCSI_USER bit was set 115 * in the flags passed to scsi_scsi_cmd(). No other completion processing 116 * takes place, even if we are running over another device driver. 117 * The lower level routines that call us here, will free the xs and restart 118 * the device's queue if such exists. 119 */ 120void 121scsi_user_done(xs) 122 struct scsi_xfer *xs; 123{ 124 struct buf *bp; 125 struct scsi_ioctl *si; 126 scsireq_t *screq; 127 struct scsi_link *sc_link; 128 129 bp = xs->bp; 130 if (!bp) { /* ALL user requests must have a buf */ 131 sc_print_addr(xs->sc_link); 132 printf("User command with no buf\n"); 133 return; 134 } 135 si = si_find(bp); 136 if (!si) { 137 sc_print_addr(xs->sc_link); 138 printf("User command with no ioctl\n"); 139 return; 140 } 141 screq = &si->si_screq; 142 sc_link = si->si_sc_link; 143 SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n")); 144 145 screq->retsts = 0; 146 screq->status = xs->status; 147 switch (xs->error) { 148 case XS_NOERROR: 149 SC_DEBUG(sc_link, SDEV_DB3, ("no error\n")); 150 screq->datalen_used = xs->datalen - xs->resid; /* probably rubbish */ 151 screq->retsts = SCCMD_OK; 152 break; 153 case XS_SENSE: 154 SC_DEBUG(sc_link, SDEV_DB3, ("have sense\n")); 155 screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN); 156 bcopy(&xs->sense, screq->sense, screq->senselen); 157 screq->retsts = SCCMD_SENSE; 158 break; 159 case XS_DRIVER_STUFFUP: 160 sc_print_addr(sc_link); 161 printf("host adapter code inconsistency\n"); 162 screq->retsts = SCCMD_UNKNOWN; 163 break; 164 case XS_TIMEOUT: 165 SC_DEBUG(sc_link, SDEV_DB3, ("timeout\n")); 166 screq->retsts = SCCMD_TIMEOUT; 167 break; 168 case XS_BUSY: 169 SC_DEBUG(sc_link, SDEV_DB3, ("busy\n")); 170 screq->retsts = SCCMD_BUSY; 171 break; 172 default: 173 sc_print_addr(sc_link); 174 printf("unknown error category from host adapter code\n"); 175 screq->retsts = SCCMD_UNKNOWN; 176 break; 177 } 178 biodone(bp); /* we're waiting on it in scsi_strategy() */ 179} 180 181 182/* Pseudo strategy function 183 * Called by scsi_do_ioctl() via physio/physstrat if there is to 184 * be data transferred, and directly if there is no data transfer. 185 * 186 * Should I reorganize this so it returns to physio instead 187 * of sleeping in scsiio_scsi_cmd? Is there any advantage, other 188 * than avoiding the probable duplicate wakeup in iodone? [PD] 189 * 190 * No, seems ok to me... [JRE] 191 * (I don't see any duplicate wakeups) 192 * 193 * Can't be used with block devices or raw_read/raw_write directly 194 * from the cdevsw/bdevsw tables because they couldn't have added 195 * the screq structure. [JRE] 196 */ 197void 198scsistrategy(bp) 199 struct buf *bp; 200{ 201 struct scsi_ioctl *si; 202 scsireq_t *screq; 203 struct scsi_link *sc_link; 204 int error; 205 int flags = 0; 206 int s; 207 208 si = si_find(bp); 209 if (!si) { 210 printf("user_strat: No ioctl\n"); 211 error = EINVAL; 212 goto bad; 213 } 214 screq = &si->si_screq; 215 sc_link = si->si_sc_link; 216 SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n")); 217 218 /* 219 * We're in trouble if physio tried to break up the transfer. 220 */ 221 if (bp->b_bcount != screq->datalen) { 222 sc_print_addr(sc_link); 223 printf("physio split the request.. cannot proceed\n"); 224 error = EIO; 225 goto bad; 226 } 227 228 if (screq->timeout == 0) { 229 error = EINVAL; 230 goto bad; 231 } 232 233 if (screq->cmdlen > sizeof(struct scsi_generic)) { 234 sc_print_addr(sc_link); 235 printf("cmdlen too big\n"); 236 error = EFAULT; 237 goto bad; 238 } 239 240 if (screq->flags & SCCMD_READ) 241 flags |= SCSI_DATA_IN; 242 if (screq->flags & SCCMD_WRITE) 243 flags |= SCSI_DATA_OUT; 244 if (screq->flags & SCCMD_TARGET) 245 flags |= SCSI_TARGET; 246 if (screq->flags & SCCMD_ESCAPE) 247 flags |= SCSI_ESCAPE; 248 249 error = scsi_scsi_cmd(sc_link, (struct scsi_generic *)screq->cmd, 250 screq->cmdlen, (u_char *)bp->b_data, screq->datalen, 251 0, /* user must do the retries *//* ignored */ 252 screq->timeout, bp, flags | SCSI_USER | SCSI_NOSLEEP); 253 254 /* because there is a bp, scsi_scsi_cmd will return immediatly */ 255 if (error) 256 goto bad; 257 258 SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n")); 259 s = splbio(); 260 while ((bp->b_flags & B_DONE) == 0) 261 tsleep(bp, PRIBIO, "scistr", 0); 262 splx(s); 263 SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n")); 264 265 return; 266 267bad: 268 bp->b_flags |= B_ERROR; 269 bp->b_error = error; 270 biodone(bp); 271} 272 273/* 274 * Something (e.g. another driver) has called us 275 * with an sc_link for a target/lun/adapter, and a scsi 276 * specific ioctl to perform, better try. 277 * If user-level type command, we must still be running 278 * in the context of the calling process 279 */ 280int 281scsi_do_ioctl(sc_link, dev, cmd, addr, flag, p) 282 struct scsi_link *sc_link; 283 dev_t dev; 284 u_long cmd; 285 caddr_t addr; 286 int flag; 287 struct proc *p; 288{ 289 int error; 290 291 SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd)); 292 293 /* If we don't have write access, just skip to the safe ones. */ 294 if ((flag & FWRITE) == 0) 295 return scsi_do_safeioctl(sc_link, dev, cmd, addr, flag, p); 296 297 switch(cmd) { 298 case SCIOCCOMMAND: { 299 scsireq_t *screq = (scsireq_t *)addr; 300 struct scsi_ioctl *si; 301 int len; 302 303 si = si_get(); 304 si->si_screq = *screq; 305 si->si_sc_link = sc_link; 306 len = screq->datalen; 307 if (len) { 308 si->si_iov.iov_base = screq->databuf; 309 si->si_iov.iov_len = len; 310 si->si_uio.uio_iov = &si->si_iov; 311 si->si_uio.uio_iovcnt = 1; 312 si->si_uio.uio_resid = len; 313 si->si_uio.uio_offset = 0; 314 si->si_uio.uio_segflg = UIO_USERSPACE; 315 si->si_uio.uio_rw = 316 (screq->flags & SCCMD_READ) ? UIO_READ : UIO_WRITE; 317 si->si_uio.uio_procp = p; 318 error = physio(scsistrategy, &si->si_bp, dev, 319 (screq->flags & SCCMD_READ) ? B_READ : B_WRITE, 320 sc_link->adapter->scsi_minphys, &si->si_uio); 321 } else { 322 /* if no data, no need to translate it.. */ 323 si->si_bp.b_flags = 0; 324 si->si_bp.b_data = 0; 325 si->si_bp.b_bcount = 0; 326 si->si_bp.b_dev = dev; 327 si->si_bp.b_proc = p; 328 scsistrategy(&si->si_bp); 329 error = si->si_bp.b_error; 330 } 331 *screq = si->si_screq; 332 si_free(si); 333 return error; 334 } 335 case SCIOCDEBUG: { 336 int level = *((int *)addr); 337 338 SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level)); 339 sc_link->flags &= ~SDEV_DBX; /* clear debug bits */ 340 if (level & 1) 341 sc_link->flags |= SDEV_DB1; 342 if (level & 2) 343 sc_link->flags |= SDEV_DB2; 344 if (level & 4) 345 sc_link->flags |= SDEV_DB3; 346 if (level & 8) 347 sc_link->flags |= SDEV_DB4; 348 return 0; 349 } 350 case OSCIOCREPROBE: { 351 struct oscsi_addr *sca = (struct oscsi_addr *)addr; 352 353 return scsi_probe_busses(sca->scbus, sca->target, sca->lun); 354 } 355 case SCIOCREPROBE: { 356 struct scsi_addr *sca = (struct scsi_addr *)addr; 357 358 return scsi_probe_busses(sca->scbus, sca->target, sca->lun); 359 } 360 case SCIOCRECONFIG: 361 case SCIOCDECONFIG: 362 return EINVAL; 363 case SCIOCRESET: { 364 if ((flag & FWRITE) == 0) 365 return EBADF; 366 scsi_scsi_cmd(sc_link, 0, 0, 0, 0, GENRETRY, 2000, NULL, 367 SCSI_RESET); 368 return 0; 369 } 370 default: 371 return scsi_do_safeioctl(sc_link, dev, cmd, addr, flag, p); 372 } 373 374#ifdef DIAGNOSTIC 375 panic("scsi_do_ioctl: impossible"); 376#endif 377} 378 379int 380scsi_do_safeioctl(sc_link, dev, cmd, addr, flag, p) 381 struct scsi_link *sc_link; 382 dev_t dev; 383 u_long cmd; 384 caddr_t addr; 385 int flag; 386 struct proc *p; 387{ 388 SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_safeioctl(0x%lx)\n", cmd)); 389 390 switch(cmd) { 391 case OSCIOCIDENTIFY: { 392 struct oscsi_addr *sca = (struct oscsi_addr *)addr; 393 394 sca->scbus = sc_link->scsibus; 395 sca->target = sc_link->target; 396 sca->lun = sc_link->lun; 397 return 0; 398 } 399 case SCIOCIDENTIFY: { 400 struct scsi_addr *sca = (struct scsi_addr *)addr; 401 402 sca->type = (sc_link->flags & SDEV_ATAPI) 403 ? TYPE_ATAPI : TYPE_SCSI; 404 sca->scbus = sc_link->scsibus; 405 sca->target = sc_link->target; 406 sca->lun = sc_link->lun; 407 return 0; 408 } 409 case SCIOCCOMMAND: 410 case SCIOCDEBUG: 411 case SCIOCREPROBE: 412 case OSCIOCREPROBE: 413 case SCIOCRESET: 414 return EBADF; 415 case SCIOCRECONFIG: 416 case SCIOCDECONFIG: 417 return EINVAL; 418 default: 419 if (sc_link->adapter->ioctl) 420 return (sc_link->adapter->ioctl)(sc_link, cmd, addr, 421 flag, p); 422 else 423 return ENOTTY; 424 } 425} 426