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