FreeBSD/Linux Kernel Cross Reference
sys/scsi/pt.c
1 /*
2 * pt: Processor Type driver.
3 *
4 * Copyright (C) 1995, HD Associates, Inc.
5 * PO Box 276
6 * Pepperell, MA 01463
7 * 508 433 5266
8 * dufault@hda.com
9 *
10 * This code is contributed to the University of California at Berkeley:
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the University of
23 * California, Berkeley and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * $FreeBSD: src/sys/scsi/pt.c,v 1.18.2.3 1999/09/05 08:21:36 peter Exp $
41 */
42
43 #include "opt_bounce.h"
44 #include "opt_scsi.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/conf.h>
51 #include <sys/kernel.h>
52 #ifdef DEVFS
53 #include <sys/devfsext.h>
54 #endif /*DEVFS*/
55 #include <scsi/scsi_all.h>
56 #include <scsi/scsiconf.h>
57
58 struct scsi_data {
59 struct buf_queue_head buf_queue;
60 };
61
62 static d_open_t ptopen;
63 static d_close_t ptclose;
64 static d_ioctl_t ptioctl;
65 static d_strategy_t ptstrategy;
66
67 #define CDEV_MAJOR 61
68 static struct cdevsw pt_cdevsw =
69 { ptopen, ptclose, rawread, rawwrite, /*61*/
70 ptioctl, nostop, nullreset, nodevtotty,/* pt */
71 seltrue, nommap, ptstrategy, "pt", NULL, -1 };
72
73 SCSI_DEVICE_ENTRIES(pt)
74
75 static void ptstart(u_int32_t unit, u_int32_t flags);
76 static void pt_strategy(struct buf *bp, struct scsi_link *sc_link);
77 static int pt_sense(struct scsi_xfer *scsi_xfer);
78
79 static struct scsi_device pt_switch =
80 {
81 pt_sense,
82 ptstart, /* we have a queue, and this is how we service it */
83 NULL,
84 NULL,
85 "pt",
86 0,
87 {0, 0},
88 SDEV_ONCE_ONLY, /* Only one open allowed */
89 ptattach,
90 "Processor",
91 ptopen,
92 sizeof(struct scsi_data),
93 T_PROCESSOR,
94 0,
95 0,
96 0,
97 0,
98 0,
99 pt_strategy,
100 };
101
102 static errval
103 ptattach(struct scsi_link *sc_link)
104 {
105 struct scsi_data *pt = sc_link->sd;
106
107 bufq_init(&pt->buf_queue);
108 return 0;
109 }
110
111 /*
112 * ptstart looks to see if there is a buf waiting for the device
113 * and that the device is not already busy. If both are true,
114 * It dequeues the buf and creates a scsi command to perform the
115 * transfer required. The transfer request will call scsi_done
116 * on completion, which will in turn call this routine again
117 * so that the next queued transfer is performed.
118 * The bufs are queued by the strategy routine (ptstrategy)
119 *
120 * This routine is also called after other non-queued requests
121 * have been made of the scsi driver, to ensure that the queue
122 * continues to be drained.
123 * ptstart() is called at splbio
124 */
125 static void
126 ptstart(unit, flags)
127 u_int32_t unit;
128 u_int32_t flags;
129 {
130 struct scsi_link *sc_link = SCSI_LINK(&pt_switch, unit);
131 struct scsi_data *pt = sc_link->sd;
132 register struct buf *bp = 0;
133 struct
134 {
135 #define PROCESSOR_SEND 0x0A
136 #define PROCESSOR_RECEIVE 0x08
137 u_char op_code;
138 u_char byte2;
139 u_char len[3];
140 u_char control;
141 } cmd;
142
143
144 SC_DEBUG(sc_link, SDEV_DB2, ("ptstart "));
145 /*
146 * See if there is a buf to do and we are not already
147 * doing one
148 */
149 while (sc_link->opennings != 0) {
150
151 /* if a special awaits, let it proceed first */
152 if (sc_link->flags & SDEV_WAITING) {
153 sc_link->flags &= ~SDEV_WAITING;
154 wakeup((caddr_t)sc_link);
155 return;
156 }
157
158 bp = bufq_first(&pt->buf_queue);
159 if (bp == NULL) { /* yes, an assign */
160 return;
161 }
162 bufq_remove(&pt->buf_queue, bp);
163
164 /*
165 * Fill out the scsi command
166 */
167 bzero(&cmd, sizeof(cmd));
168 if ((bp->b_flags & B_READ) == B_WRITE) {
169 cmd.op_code = PROCESSOR_SEND;
170 flags |= SCSI_DATA_OUT;
171 } else {
172 cmd.op_code = PROCESSOR_RECEIVE;
173 flags |= SCSI_DATA_IN;
174 }
175
176 scsi_uto3b(bp->b_bcount, cmd.len);
177 /*
178 * go ask the adapter to do all this for us
179 */
180 if (scsi_scsi_cmd(sc_link,
181 (struct scsi_generic *) &cmd,
182 sizeof(cmd),
183 (u_char *) bp->b_un.b_addr,
184 bp->b_bcount,
185 0,
186 10000,
187 bp,
188 flags) == SUCCESSFULLY_QUEUED) {
189 } else {
190 printf("pt%ld: oops not queued\n", unit);
191 bp->b_flags |= B_ERROR;
192 bp->b_error = EIO;
193 biodone(bp);
194 }
195 } /* go back and see if we can cram more work in.. */
196 }
197
198 static void
199 pt_strategy(struct buf *bp, struct scsi_link *sc_link)
200 {
201 unsigned char unit;
202 u_int32_t opri;
203 struct scsi_data *pt;
204
205 unit = minor((bp->b_dev));
206 pt = sc_link->sd;
207
208 opri = splbio();
209
210 /*
211 * Use a bounce buffer if necessary
212 */
213 #ifdef BOUNCE_BUFFERS
214 if (sc_link->flags & SDEV_BOUNCE)
215 vm_bounce_alloc(bp);
216 #endif
217
218 /*
219 * Place it in the queue of activities for this tape
220 * at the end (a bit silly because we only have one user..
221 * (but it could fork() ))
222 */
223 bufq_insert_tail(&pt->buf_queue, bp);
224
225 /*
226 * Tell the device to get going on the transfer if it's
227 * not doing anything, otherwise just wait for completion
228 * (All a bit silly if we're only allowing 1 open but..)
229 */
230 ptstart(unit, 0);
231
232 splx(opri);
233 return;
234 }
235
236 /*
237 * sense handler: Called to determine what to do when the
238 * device returns a CHECK CONDITION.
239 *
240 * For the processor type devices we try to handle the "info" field.
241 */
242
243 static int
244 pt_sense(struct scsi_xfer *xs)
245 {
246 struct scsi_sense_data *sense = &(xs->sense);
247 struct buf *bp;
248
249 long resid;
250
251 if ((sense->error_code & SSD_ERRCODE_VALID) == 0 ||
252 (sense->ext.extended.flags & SSD_ILI) == 0) {
253 return SCSIRET_CONTINUE; /* let the default handler handle it */
254 }
255
256 resid = ntohl(*((int32_t *) sense->ext.extended.info));
257
258 bp = xs->bp;
259
260 if (resid < 0) {
261 /* It synthesized data in order to fill our request.
262 * Move resid back to cover this.
263 */
264 xs->resid = -resid;
265 xs->flags |= SCSI_RESID_VALID;
266 return 0;
267 }
268 else {
269 /* It wanted to send more data. We can't really do anything
270 * about this.
271 */
272 return SCSIRET_CONTINUE;
273 }
274 }
275
276 static pt_devsw_installed = 0;
277
278 static void pt_drvinit(void *unused)
279 {
280 dev_t dev;
281 #ifdef DEVFS
282 int unit;
283 #endif
284
285 if( ! pt_devsw_installed ) {
286 dev = makedev(CDEV_MAJOR, 0);
287 cdevsw_add(&dev,&pt_cdevsw, NULL);
288 pt_devsw_installed = 1;
289 #ifdef DEVFS
290 /* XXX only 1 unit. */
291 for (unit = 0; unit < 1; unit++) {
292 /* XXX not saving tokens yet. */
293 devfs_add_devswf(&pt_cdevsw, unit, DV_CHR,
294 UID_ROOT, GID_WHEEL, 0600,
295 "pt%d", unit);
296 devfs_add_devswf(&pt_cdevsw, unit | SCSI_CONTROL_MASK,
297 DV_CHR,
298 UID_ROOT, GID_WHEEL, 0600,
299 "pt%d.ctl", unit);
300 }
301 #endif
302 }
303 }
304
305 SYSINIT(ptdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,pt_drvinit,NULL)
306
307
Cache object: 288e9c9fa76959875987ed8b8d0d1718
|