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