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