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