1 /* $NetBSD: scsipi_ioctl.c,v 1.10 1994/10/30 21:49:21 cgd Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Charles Hannum. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Charles Hannum. 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Contributed by HD Associates (hd@world.std.com). 34 * Copyright (c) 1992, 1993 HD Associates 35 * 36 * Berkeley style copyright. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/errno.h> 41 #include <sys/param.h> 42 #include <sys/malloc.h> 43 #include <sys/buf.h> 44 #include <sys/proc.h> 45 #include <sys/device.h> 46 47 #include <scsi/scsi_all.h> 48 #include <scsi/scsiconf.h> 49 #include <sys/scsiio.h> 50 51 void scsierr __P((struct buf *, int)); 52 53 /* 54 * We need to maintain an assocation between the buf and the SCSI request 55 * structure. We do this with a simple array of scsi_ioctl structures below. 56 * XXX The free structures should probably be in a linked list. 57 */ 58 #define NIOCTL 16 59 60 struct scsi_ioctl { 61 struct buf *si_bp; 62 scsireq_t si_screq; 63 struct scsi_link *si_sc_link; 64 struct uio si_uio; 65 struct iovec si_iov; 66 } scsi_ioctl[NIOCTL]; 67 68 struct scsi_ioctl * 69 si_get(bp) 70 struct buf *bp; 71 { 72 int s = splbio(); 73 struct scsi_ioctl *si; 74 int error; 75 76 for (;;) { 77 for (si = scsi_ioctl; si < &scsi_ioctl[NIOCTL]; si++) 78 if (si->si_bp == 0) { 79 si->si_bp = bp; 80 splx(s); 81 return si; 82 } 83 error = tsleep(scsi_ioctl, PRIBIO | PCATCH, "siget", 0); 84 if (error) { 85 splx(s); 86 return 0; 87 } 88 } 89 } 90 91 void 92 si_free(si) 93 struct scsi_ioctl *si; 94 { 95 int s = splbio(); 96 97 si->si_bp = 0; 98 wakeup(scsi_ioctl); 99 splx(s); 100 } 101 102 struct scsi_ioctl * 103 si_find(bp) 104 struct buf *bp; 105 { 106 int s = splbio(); 107 struct scsi_ioctl *si; 108 109 for (si = scsi_ioctl; si < &scsi_ioctl[NIOCTL]; si++) 110 if (si->si_bp == bp) { 111 splx(s); 112 return si; 113 } 114 splx(s); 115 return 0; 116 } 117 118 /* 119 * We let the user interpret his own sense in the generic scsi world. 120 * This routine is called at interrupt time if the SCSI_USER bit was set 121 * in the flags passed to scsi_scsi_cmd(). No other completion processing 122 * takes place, even if we are running over another device driver. 123 * The lower level routines that call us here, will free the xs and restart 124 * the device's queue if such exists. 125 */ 126 void 127 scsi_user_done(xs) 128 struct scsi_xfer *xs; 129 { 130 struct buf *bp; 131 scsireq_t *screq; 132 struct scsi_ioctl *si; 133 134 bp = xs->bp; 135 if (!bp) { /* ALL user requests must have a buf */ 136 sc_print_addr(xs->sc_link); 137 printf("User command with no buf\n"); 138 return; 139 } 140 si = si_find(bp); 141 if (!si) { 142 sc_print_addr(xs->sc_link); 143 printf("User command with no ioctl\n"); 144 return; 145 } 146 screq = &si->si_screq; 147 148 SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n")); 149 screq->retsts = 0; 150 screq->status = xs->status; 151 switch (xs->error) { 152 case XS_NOERROR: 153 SC_DEBUG(xs->sc_link, SDEV_DB3, ("no error\n")); 154 screq->datalen_used = xs->datalen - xs->resid; /* probably rubbish */ 155 screq->retsts = SCCMD_OK; 156 break; 157 case XS_SENSE: 158 SC_DEBUG(xs->sc_link, SDEV_DB3, ("have sense\n")); 159 screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN); 160 bcopy(&xs->sense, screq->sense, screq->senselen); 161 screq->retsts = SCCMD_SENSE; 162 break; 163 case XS_DRIVER_STUFFUP: 164 sc_print_addr(xs->sc_link); 165 printf("host adapter code inconsistency\n"); 166 screq->retsts = SCCMD_UNKNOWN; 167 break; 168 case XS_TIMEOUT: 169 SC_DEBUG(xs->sc_link, SDEV_DB3, ("timeout\n")); 170 screq->retsts = SCCMD_TIMEOUT; 171 break; 172 case XS_BUSY: 173 SC_DEBUG(xs->sc_link, SDEV_DB3, ("busy\n")); 174 screq->retsts = SCCMD_BUSY; 175 break; 176 default: 177 sc_print_addr(xs->sc_link); 178 printf("unknown error category from host adapter code\n"); 179 screq->retsts = SCCMD_UNKNOWN; 180 break; 181 } 182 biodone(bp); /* we're waiting on it in scsi_strategy() */ 183 184 si_free(si); 185 } 186 187 188 /* Pseudo strategy function 189 * Called by scsi_do_ioctl() via physio/physstrat if there is to 190 * be data transfered, and directly if there is no data transfer. 191 * 192 * Should I reorganize this so it returns to physio instead 193 * of sleeping in scsiio_scsi_cmd? Is there any advantage, other 194 * than avoiding the probable duplicate wakeup in iodone? [PD] 195 * 196 * No, seems ok to me... [JRE] 197 * (I don't see any duplicate wakeups) 198 * 199 * Can't be used with block devices or raw_read/raw_write directly 200 * from the cdevsw/bdevsw tables because they couldn't have added 201 * the screq structure. [JRE] 202 */ 203 void 204 scsistrategy(bp) 205 struct buf *bp; 206 { 207 int err; 208 struct scsi_ioctl *si; 209 scsireq_t *screq; 210 struct scsi_link *sc_link; 211 int flags = 0; 212 int s; 213 214 si = si_find(bp); 215 if (!si) { 216 printf("user_strat: No ioctl\n"); 217 scsierr(bp, EINVAL); 218 return; 219 } 220 screq = &si->si_screq; 221 222 sc_link = si->si_sc_link; 223 if (!sc_link) { 224 printf("user_strat: No link pointer\n"); 225 scsierr(bp, EINVAL); 226 goto out; 227 } 228 SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n")); 229 230 /* 231 * We're in trouble if physio tried to break up the transfer. 232 */ 233 if (bp->b_bcount != screq->datalen) { 234 sc_print_addr(sc_link); 235 printf("physio split the request.. cannot proceed\n"); 236 scsierr(bp, EIO); 237 goto out; 238 } 239 240 if (screq->timeout == 0) { 241 scsierr(bp, EINVAL); 242 goto out; 243 } 244 245 if (screq->cmdlen > sizeof(struct scsi_generic)) { 246 sc_print_addr(sc_link); 247 printf("cmdlen too big\n"); 248 scsierr(bp, EFAULT); 249 goto out; 250 } 251 252 if (screq->flags & SCCMD_READ) 253 flags |= SCSI_DATA_IN; 254 if (screq->flags & SCCMD_WRITE) 255 flags |= SCSI_DATA_OUT; 256 if (screq->flags & SCCMD_TARGET) 257 flags |= SCSI_TARGET; 258 if (screq->flags & SCCMD_ESCAPE) 259 flags |= SCSI_ESCAPE; 260 261 err = scsi_scsi_cmd(sc_link, (struct scsi_generic *)screq->cmd, 262 screq->cmdlen, (u_char *)bp->b_data, screq->datalen, 263 0, /* user must do the retries *//* ignored */ 264 screq->timeout, bp, flags | SCSI_USER); 265 266 /* because there is a bp, scsi_scsi_cmd will return immediatly */ 267 if (err) { 268 scsierr(bp, err); 269 goto out; 270 } 271 SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n")); 272 s = splbio(); 273 while (!(bp->b_flags & B_DONE)) 274 tsleep(bp, PRIBIO, "scistr", 0); 275 splx(s); 276 SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n")); 277 278 out: 279 si_free(si); 280 } 281 282 /* 283 * Something (e.g. another driver) has called us 284 * with an sc_link for a target/lun/adapter, and a scsi 285 * specific ioctl to perform, better try. 286 * If user-level type command, we must still be running 287 * in the context of the calling process 288 */ 289 int 290 scsi_do_ioctl(sc_link, dev, cmd, addr, f) 291 struct scsi_link *sc_link; 292 dev_t dev; 293 u_long cmd; 294 caddr_t addr; 295 int f; 296 { 297 int error; 298 299 SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%lx)\n", cmd)); 300 switch(cmd) { 301 case SCIOCCOMMAND: { 302 /* 303 * You won't believe this, but the arg copied in 304 * from the user space, is on the kernel stack 305 * for this process, so we can't write 306 * to it at interrupt time.. 307 * we need to copy it in and out! 308 * Make a static copy using malloc! 309 */ 310 scsireq_t *screq = (scsireq_t *)addr; 311 struct buf *bp; 312 struct scsi_ioctl *si; 313 caddr_t daddr; 314 int len; 315 316 bp = malloc(sizeof(struct buf), M_TEMP, M_WAITOK); 317 bzero(bp, sizeof(struct buf)); 318 daddr = screq->databuf; 319 bp->b_bcount = len = screq->datalen; 320 si = si_get(bp); 321 if (!si) { 322 scsierr(bp, EINTR); 323 return EINTR; 324 } 325 si->si_screq = *screq; 326 si->si_sc_link = sc_link; 327 if (len) { 328 si->si_iov.iov_base = daddr; 329 si->si_iov.iov_len = len; 330 si->si_uio.uio_iov = &si->si_iov; 331 si->si_uio.uio_iovcnt = 1; 332 si->si_uio.uio_offset = 0; 333 si->si_uio.uio_segflg = UIO_USERSPACE; 334 si->si_uio.uio_rw = 335 (screq->flags & SCCMD_READ) ? UIO_READ : UIO_WRITE; 336 si->si_uio.uio_procp = curproc; /* XXX */ 337 error = physio(scsistrategy, bp, dev, 338 (screq->flags & SCCMD_READ) ? B_READ : B_WRITE, 339 sc_link->adapter->scsi_minphys, &si->si_uio); 340 } else { 341 /* if no data, no need to translate it.. */ 342 bp->b_data = 0; 343 bp->b_dev = -1; /* irrelevant info */ 344 bp->b_flags = 0; 345 scsistrategy(bp); 346 error = bp->b_error; 347 } 348 free(bp, M_TEMP); 349 return error; 350 } 351 case SCIOCDEBUG: { 352 int level = *((int *)addr); 353 354 SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level)); 355 sc_link->flags &= ~SDEV_DBX; /* clear debug bits */ 356 if (level & 1) 357 sc_link->flags |= SDEV_DB1; 358 if (level & 2) 359 sc_link->flags |= SDEV_DB2; 360 if (level & 4) 361 sc_link->flags |= SDEV_DB3; 362 if (level & 8) 363 sc_link->flags |= SDEV_DB4; 364 return 0; 365 } 366 case SCIOCREPROBE: { 367 struct scsi_addr *sca = (struct scsi_addr *)addr; 368 369 return scsi_probe_busses(sca->scbus, sca->target, sca->lun); 370 } 371 case SCIOCRECONFIG: 372 case SCIOCDECONFIG: 373 return EINVAL; 374 case SCIOCIDENTIFY: { 375 struct scsi_addr *sca = (struct scsi_addr *)addr; 376 377 sca->scbus = sc_link->scsibus; 378 sca->target = sc_link->target; 379 sca->lun = sc_link->lun; 380 return 0; 381 } 382 default: 383 return ENOTTY; 384 } 385 386 #ifdef DIAGNOSTIC 387 panic("scsi_do_ioctl: impossible"); 388 #endif 389 } 390 391 void 392 scsierr(bp, error) 393 struct buf *bp; 394 int error; 395 { 396 397 bp->b_flags |= B_ERROR; 398 bp->b_error = error; 399 biodone(bp); 400 } 401