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