1 /* 2 * Contributed by HD Associates (hd@world.std.com). 3 * Copyright (c) 1992, 1993 HD Associates 4 * 5 * Berkeley style copyright. 6 */ 7 8 #include <sys/types.h> 9 #include <sys/errno.h> 10 #include <sys/param.h> 11 #include <sys/malloc.h> 12 #include <sys/buf.h> 13 #include <sys/proc.h> 14 #include <sys/device.h> 15 16 #include <scsi/scsi_all.h> 17 #include <scsi/scsiconf.h> 18 #include <sys/scsiio.h> 19 20 #define b_screq b_driver1 /* XXX */ 21 #define b_sc_link b_driver2 /* XXX */ 22 23 /* 24 * We let the user interpret his own sense in the generic scsi world. 25 * This routine is called at interrupt time if the SCSI_USER bit was set 26 * in the flags passed to scsi_scsi_cmd(). No other completion processing 27 * takes place, even if we are running over another device driver. 28 * The lower level routines that call us here, will free the xs and restart 29 * the device's queue if such exists. 30 */ 31 #ifndef min 32 #define min(A,B) ((A<B) ? A : B) 33 #endif 34 35 void scsierr __P((struct buf *, int)); 36 37 void 38 scsi_user_done(xs) 39 struct scsi_xfer *xs; 40 { 41 struct buf *bp; 42 scsireq_t *screq; 43 44 bp = xs->bp; 45 if (!bp) { /* ALL user requests must have a buf */ 46 sc_print_addr(xs->sc_link); 47 printf("User command with no buf\n"); 48 return; 49 } 50 screq = bp->b_screq; 51 if (!screq) { /* Is it one of ours? (the SCSI_USER bit says it is) */ 52 sc_print_addr(xs->sc_link); 53 printf("User command with no request\n"); 54 return; 55 } 56 57 SC_DEBUG(xs->sc_link, SDEV_DB2, ("user-done\n")); 58 screq->retsts = 0; 59 screq->status = xs->status; 60 switch(xs->error) { 61 case XS_NOERROR: 62 SC_DEBUG(xs->sc_link, SDEV_DB3, ("no error\n")); 63 screq->datalen_used = xs->datalen - xs->resid; /* probably rubbish */ 64 screq->retsts = SCCMD_OK; 65 break; 66 67 case XS_SENSE: 68 SC_DEBUG(xs->sc_link, SDEV_DB3, ("have sense\n")); 69 screq->senselen_used = min(sizeof(xs->sense), SENSEBUFLEN); 70 bcopy(&xs->sense, screq->sense, screq->senselen); 71 screq->retsts = SCCMD_SENSE; 72 break; 73 74 case XS_DRIVER_STUFFUP: 75 sc_print_addr(xs->sc_link); 76 printf("host adapter code inconsistency\n"); 77 screq->retsts = SCCMD_UNKNOWN; 78 break; 79 80 case XS_TIMEOUT: 81 SC_DEBUG(xs->sc_link, SDEV_DB3, ("timeout\n")); 82 screq->retsts = SCCMD_TIMEOUT; 83 break; 84 85 case XS_BUSY: 86 SC_DEBUG(xs->sc_link, SDEV_DB3, ("busy\n")); 87 screq->retsts = SCCMD_BUSY; 88 break; 89 90 default: 91 sc_print_addr(xs->sc_link); 92 printf("unknown error category from host adapter code\n"); 93 screq->retsts = SCCMD_UNKNOWN; 94 break; 95 } 96 biodone(bp); /* we're waiting on it in scsi_strategy() */ 97 return; /* it'll free the xs and restart any queue */ 98 } 99 100 101 /* Pseudo strategy function 102 * Called by scsi_do_ioctl() via physio/physstrat if there is to 103 * be data transfered, and directly if there is no data transfer. 104 * 105 * Should I reorganize this so it returns to physio instead 106 * of sleeping in scsiio_scsi_cmd? Is there any advantage, other 107 * than avoiding the probable duplicate wakeup in iodone? [PD] 108 * 109 * No, seems ok to me... [JRE] 110 * (I don't see any duplicate wakeups) 111 * 112 * Can't be used with block devices or raw_read/raw_write directly 113 * from the cdevsw/bdevsw tables because they couldn't have added 114 * the screq structure. [JRE] 115 */ 116 void scsistrategy(struct buf *bp) 117 { 118 int err; 119 struct scsi_link *sc_link = bp->b_sc_link; 120 scsireq_t *screq; 121 u_int32 flags = 0; 122 int s; 123 124 if (!sc_link) { 125 printf("user_strat: No link pointer\n"); 126 scsierr(bp, EINVAL); 127 return; 128 } 129 SC_DEBUG(sc_link, SDEV_DB2, ("user_strategy\n")); 130 screq = bp->b_screq; 131 if (!screq) { 132 sc_print_addr(sc_link); 133 printf("No request block\n"); 134 scsierr(bp, EINVAL); 135 return; 136 } 137 138 /* We're in trouble if physio tried to break up the 139 * transfer: 140 */ 141 if (bp->b_bcount != screq->datalen) { 142 sc_print_addr(sc_link); 143 printf("physio split the request.. cannot proceed\n"); 144 scsierr(bp, EIO); 145 return; 146 } 147 148 if (screq->timeout == 0) { 149 scsierr(bp, EINVAL); 150 return; 151 } 152 153 if (screq->cmdlen > sizeof(struct scsi_generic)) { 154 sc_print_addr(sc_link); 155 printf("cmdlen too big "); 156 scsierr(bp, EFAULT); 157 return; 158 } 159 160 if (screq->flags & SCCMD_READ) 161 flags |= SCSI_DATA_IN; 162 163 if (screq->flags & SCCMD_WRITE) 164 flags |= SCSI_DATA_OUT; 165 166 if (screq->flags & SCCMD_TARGET) 167 flags |= SCSI_TARGET; 168 169 if (screq->flags & SCCMD_ESCAPE) 170 flags |= SCSI_ESCAPE; 171 172 err = scsi_scsi_cmd(sc_link, 173 (struct scsi_generic *)screq->cmd, 174 screq->cmdlen, 175 (u_char *)bp->b_un.b_addr, 176 screq->datalen, 177 0, /* user must do the retries *//* ignored */ 178 screq->timeout, 179 bp, 180 flags | SCSI_USER); 181 182 /* because there is a bp, scsi_scsi_cmd will return immediatly */ 183 if (err) { 184 scsierr(bp, err); 185 return; 186 } 187 SC_DEBUG(sc_link, SDEV_DB3, ("about to sleep\n")); 188 s = splbio(); 189 while (!(bp->b_flags & B_DONE)) 190 tsleep(bp, PRIBIO, "scistr", 0); 191 splx(s); 192 SC_DEBUG(sc_link, SDEV_DB3, ("back from sleep\n")); 193 return; 194 } 195 196 void scsiminphys(struct buf *bp) 197 { 198 /*XXX*//* call the adapter's minphys */ 199 } 200 201 202 /* 203 * Something (e.g. another driver) has called us 204 * with an sc_link for a target/lun/adapter, and a scsi 205 * specific ioctl to perform, better try. 206 * If user-level type command, we must still be running 207 * in the context of the calling process 208 */ 209 int 210 scsi_do_ioctl(struct scsi_link *sc_link, int cmd, caddr_t addr, int f) 211 { 212 int error = 0; 213 int phys; 214 215 SC_DEBUG(sc_link, SDEV_DB2, ("scsi_do_ioctl(0x%x)\n", cmd)); 216 switch(cmd) { 217 #ifndef __NetBSD__ 218 case SCIOCCOMMAND: 219 { 220 /* 221 * You won't believe this, but the arg copied in 222 * from the user space, is on the kernel stack 223 * for this process, so we can't write 224 * to it at interrupt time.. 225 * we need to copy it in and out! 226 * Make a static copy using malloc! 227 */ 228 scsireq_t *screq2 = (scsireq_t *)addr; 229 scsireq_t *screq = (scsireq_t *)addr; 230 int rwflag = (screq->flags & SCCMD_READ) ? B_READ : B_WRITE; 231 struct buf *bp; 232 caddr_t d_addr; 233 int len; 234 235 if ((unsigned int)screq < KERNBASE) { 236 screq = malloc(sizeof(scsireq_t), 237 M_TEMP, M_WAITOK); 238 bcopy(screq2, screq, sizeof(scsireq_t)); 239 } 240 bp = malloc(sizeof (struct buf), M_TEMP, M_WAITOK); 241 bzero(bp, sizeof(struct buf)); 242 d_addr = screq->databuf; 243 bp->b_bcount = len = screq->datalen; 244 bp->b_screq = screq; 245 bp->b_sc_link = sc_link; 246 if (len) { 247 /* have data, translate it. (physio)*/ 248 #ifdef __NetBSD__ 249 #error "dev, mincntfn & uio need defining" 250 error = physio(scsistrategy, bp, dev, rwflag, 251 mincntfn, uio); 252 #else 253 error = physio(scsistrategy, 0, bp, 0, rwflag, 254 d_addr, &len, curproc); 255 #endif 256 } else { 257 /* if no data, no need to translate it.. */ 258 bp->b_un.b_addr = 0; 259 bp->b_dev = -1; /* irrelevant info */ 260 bp->b_flags = 0; 261 262 scsistrategy(bp); 263 error = bp->b_error; 264 } 265 free(bp, M_TEMP); 266 if ((unsigned int)screq2 < KERNBASE) { 267 bcopy(screq, screq2, sizeof(scsireq_t)); 268 free(screq, M_TEMP); 269 } 270 break; 271 } 272 #endif /* !NetBSD */ 273 case SCIOCDEBUG: 274 { 275 int level = *((int *)addr); 276 SC_DEBUG(sc_link, SDEV_DB3, ("debug set to %d\n", level)); 277 sc_link->flags &= ~SDEV_DBX; /*clear debug bits */ 278 if (level & 1) 279 sc_link->flags |= SDEV_DB1; 280 if (level & 2) 281 sc_link->flags |= SDEV_DB2; 282 if (level & 4) 283 sc_link->flags |= SDEV_DB3; 284 if (level & 8) 285 sc_link->flags |= SDEV_DB4; 286 error = 0; 287 break; 288 } 289 case SCIOCREPROBE: 290 { 291 extern int scsibus; 292 struct scsi_addr *sca = (struct scsi_addr *) addr; 293 294 error = scsi_probe_busses(sca->scbus, sca->target, sca->lun); 295 break; 296 } 297 case SCIOCRECONFIG: 298 case SCIOCDECONFIG: 299 error = EINVAL; 300 break; 301 case SCIOCIDENTIFY: 302 { 303 struct scsi_addr *sca = (struct scsi_addr *) addr; 304 sca->scbus = sc_link->scsibus; 305 sca->target = sc_link->target; 306 sca->lun = sc_link->lun; 307 break; 308 } 309 310 default: 311 error = ENOTTY; 312 break; 313 } 314 315 return error; 316 } 317 318 void 319 scsierr(bp, error) 320 struct buf *bp; 321 int error; 322 { 323 324 bp->b_flags |= B_ERROR; 325 bp->b_error = error; 326 biodone(bp); 327 return; 328 } 329 330