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