Home | History | Annotate | Line # | Download | only in scsipi
scsipi_ioctl.c revision 1.2
      1 /*
      2  * Contributed by HD Associates (hd (at) 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 av_forw		/* XXX */
     21 #define	b_sc_link av_back	/* 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