FreeBSD/Linux Kernel Cross Reference
sys/scsi/rz_cpu.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: rz_cpu.c,v $
29 * Revision 2.9 93/05/15 19:43:23 mrt
30 * machparam.h -> machspl.h
31 *
32 * Revision 2.8 93/02/01 09:55:39 danner
33 * Removed unused variable 'tgt' from sccpu_act_as_target().
34 * [93/01/25 jfriedl]
35 *
36 * Revision 2.7 93/01/14 17:55:15 danner
37 * Some more code, good enough for experimenting.
38 * [92/12/10 20:22:19 af]
39 *
40 * Revision 2.6 92/08/03 17:53:22 jfriedl
41 * removed silly prototypes
42 * [92/08/02 jfriedl]
43 *
44 * Revision 2.5 92/05/21 17:23:22 jfriedl
45 * Cleanup to quiet gcc warnings.
46 * [92/05/16 jfriedl]
47 *
48 * Revision 2.4 92/04/06 23:22:56 rpd
49 * On bad errors, be loquacious and decode all sense data.
50 * Do not retry IO_INTERNAL operations, cuz we donno what it is.
51 * [92/04/06 af]
52 *
53 * Revision 2.3 92/02/23 22:44:15 elf
54 * Changed the interface of a number of functions not to
55 * require the scsi_softc pointer any longer. It was
56 * mostly unused, now it can be found via tgt->masterno.
57 * [92/02/22 19:30:48 af]
58 *
59 * Revision 2.2 91/08/24 12:27:47 af
60 * Created.
61 * [91/08/02 03:52:11 af]
62 *
63 */
64 /*
65 * File: rz_cpu.c
66 * Author: Alessandro Forin, Carnegie Mellon University
67 * Date: 7/91
68 *
69 * Top layer of the SCSI driver: interface with the MI.
70 * This file contains operations specific to CPU-like devices.
71 *
72 * We handle here the case of simple devices which do not use any
73 * sophisticated host-to-host communication protocol, they look
74 * very much like degenerative cases of TAPE devices.
75 *
76 * For documentation and debugging, we also provide code to act like one.
77 */
78
79 #include <mach/std_types.h>
80 #include <scsi/compat_30.h>
81
82 #include <scsi/scsi.h>
83 #include <scsi/scsi_defs.h>
84 #include <scsi/rz.h>
85
86
87
88 void sccpu_act_as_target(); /* forwards */
89 void sccpu_start();
90
91 /*
92 * This function decides which 'protocol' we well speak
93 * to a cpu target. For now the decision is left to a
94 * global var. XXXXXXX
95 */
96 extern scsi_devsw_t scsi_host;
97 scsi_devsw_t *scsi_cpu_protocol = /* later &scsi_host*/
98 &scsi_devsw[SCSI_CPU];
99
100 void sccpu_new_initiator(self, initiator)
101 target_info_t *self, *initiator;
102 {
103 initiator->dev_ops = scsi_cpu_protocol;
104 if (initiator == self) {
105 self->flags = TGT_DID_SYNCH|TGT_FULLY_PROBED|TGT_ONLINE|
106 TGT_ALIVE|TGT_US;
107 self->dev_info.cpu.req_pending = FALSE;
108 } else {
109 initiator->flags = TGT_ONLINE|TGT_ALIVE;
110 initiator->dev_info.cpu.req_pending = TRUE;
111 }
112 }
113
114 void sccpu_strategy(ior)
115 register io_req_t ior;
116 {
117 void sccpu_start();
118
119 rz_simpleq_strategy(ior, sccpu_start);
120 }
121
122 void sccpu_start(tgt, done)
123 target_info_t *tgt;
124 boolean_t done;
125 {
126 io_req_t head, ior;
127 scsi_ret_t ret;
128
129 /* this is to the doc & debug code mentioned in the beginning */
130 if (!done && tgt->dev_info.cpu.req_pending) {
131 sccpu_act_as_target( tgt);
132 return;
133 }
134
135 ior = tgt->ior;
136 if (ior == 0)
137 return;
138
139 if (done) {
140
141 /* see if we must retry */
142 if ((tgt->done == SCSI_RET_RETRY) &&
143 ((ior->io_op & IO_INTERNAL) == 0)) {
144 delay(1000000);/*XXX*/
145 goto start;
146 } else
147 /* got a bus reset ? shouldn't matter */
148 if ((tgt->done == (SCSI_RET_ABORTED|SCSI_RET_RETRY)) &&
149 ((ior->io_op & IO_INTERNAL) == 0)) {
150 goto start;
151 } else
152
153 /* check completion status */
154
155 if (tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) {
156 scsi_sense_data_t *sns;
157
158 ior->io_op = ior->io_temporary;
159 ior->io_error = D_IO_ERROR;
160 ior->io_op |= IO_ERROR;
161
162 sns = (scsi_sense_data_t *)tgt->cmd_ptr;
163 if (scsi_debug)
164 scsi_print_sense_data(sns);
165
166 if (scsi_check_sense_data(tgt, sns)) {
167 if (sns->u.xtended.ili) {
168 if (ior->io_op & IO_READ) {
169 int residue;
170
171 residue = sns->u.xtended.info0 << 24 |
172 sns->u.xtended.info1 << 16 |
173 sns->u.xtended.info2 << 8 |
174 sns->u.xtended.info3;
175 if (scsi_debug)
176 printf("Cpu Short Read (%d)\n", residue);
177 /*
178 * NOTE: residue == requested - actual
179 * We only care if > 0
180 */
181 if (residue < 0) residue = 0;/* sanity */
182 ior->io_residual += residue;
183 ior->io_error = 0;
184 ior->io_op &= ~IO_ERROR;
185 /* goto ok */
186 }
187 }
188 }
189 }
190
191 else if (tgt->done != SCSI_RET_SUCCESS) {
192
193 if (tgt->done == SCSI_RET_NEED_SENSE) {
194
195 ior->io_temporary = ior->io_op;
196 ior->io_op = IO_INTERNAL;
197 if (scsi_debug)
198 printf("[NeedSns x%x x%x]", ior->io_residual, ior->io_count);
199 scsi_request_sense(tgt, ior, 0);
200 return;
201
202 } else if (tgt->done == SCSI_RET_RETRY) {
203 /* only retry here READs and WRITEs */
204 if ((ior->io_op & IO_INTERNAL) == 0) {
205 ior->io_residual = 0;
206 goto start;
207 } else{
208 ior->io_error = D_WOULD_BLOCK;
209 ior->io_op |= IO_ERROR;
210 }
211 } else {
212 ior->io_error = D_IO_ERROR;
213 ior->io_op |= IO_ERROR;
214 }
215 }
216
217 if (scsi_debug)
218 printf("[Resid x%x]", ior->io_residual);
219
220 /* dequeue next one */
221 head = ior;
222
223 simple_lock(&tgt->target_lock);
224 ior = head->io_next;
225 tgt->ior = ior;
226 if (ior)
227 ior->io_prev = head->io_prev;
228 simple_unlock(&tgt->target_lock);
229
230 iodone(head);
231
232 if (ior == 0)
233 return;
234 }
235 ior->io_residual = 0;
236 start:
237 if (ior->io_op & IO_READ) {
238 ret = scsi_receive( tgt, ior );
239 } else if ((ior->io_op & IO_INTERNAL) == 0) {
240 ret = scsi_send( tgt, ior );
241 }
242 }
243
244
245 /*
246 * This is a simple code to make us act as a dumb
247 * processor type. Use for debugging only.
248 */
249 static struct io_req sccpu_ior;
250 vm_offset_t sccpu_buffer; /* set this with debugger */
251
252 void sccpu_act_as_target(self)
253 target_info_t *self;
254 {
255 static char inq_data[] = "\3\0\1\0\040\0\0\0Mach3.0 Processor Link v0.1";
256 static char sns_data[] = "\160\0\0\0\0\0\0\0\0";
257
258 self->dev_info.cpu.req_pending = FALSE;
259 sccpu_ior.io_next = 0;
260 #define MAXSIZE 1024*64
261 sccpu_ior.io_count = (MAXSIZE < self->dev_info.cpu.req_len) ?
262 MAXSIZE : self->dev_info.cpu.req_len;
263
264 switch (self->dev_info.cpu.req_cmd) {
265 case SCSI_CMD_INQUIRY:
266 sccpu_ior.io_data = inq_data; break;
267 case SCSI_CMD_REQUEST_SENSE:
268 sccpu_ior.io_data = sns_data; break;
269 default:
270 if (sccpu_buffer == 0) {
271 /* ( read my lips :-) */
272 extern char end[];
273 sccpu_buffer = trunc_page(end);
274 }
275 sccpu_ior.io_data = (char*)sccpu_buffer; break;
276 }
277
278 if (self->dev_info.cpu.req_cmd == SCSI_CMD_SEND) {
279 self->cur_cmd = SCSI_CMD_READ;
280 sccpu_ior.io_op = IO_READ;
281 } else {
282 self->cur_cmd = SCSI_CMD_WRITE;
283 sccpu_ior.io_op = IO_WRITE;
284 }
285 self->ior = &sccpu_ior;
286 }
287
288 /*#define PERF*/
289 #ifdef PERF
290 int test_read_size = 512;
291 int test_read_nreads = 1000;
292 int test_read_bdev = 0;
293 int test_read_or_write = 1;
294
295 #include <sys/time.h>
296 #include <machine/machspl.h> /* spl */
297
298 test_read(max)
299 {
300 int i, ssk, usecs;
301 struct timeval start, stop;
302 spl_t s;
303
304 if (max != 0)
305 test_read_nreads = max;
306
307 s = spl0();
308 start = time;
309 if (test_read_or_write) read_test(); else write_test();
310 stop = time;
311 splx(s);
312
313 usecs = stop.tv_usec - start.tv_usec;
314 if (usecs < 0) {
315 stop.tv_sec -= 1;
316 usecs += 1000000;
317 }
318 printf("Size %d count %d time %3d sec %d us\n",
319 test_read_size, test_read_nreads,
320 stop.tv_sec - start.tv_sec, usecs);
321 }
322
323 read_test()
324 {
325 struct io_req io, io1;
326 register int i;
327
328 bzero(&io, sizeof(io));
329 io.io_unit = test_read_bdev;
330 io.io_op = IO_READ;
331 io.io_count = test_read_size;
332 io.io_data = (char*)sccpu_buffer;
333 io1 = io;
334
335 sccpu_strategy(&io);
336 for (i = 1; i < test_read_nreads; i += 2) {
337 io1.io_op = IO_READ;
338 sccpu_strategy(&io1);
339 iowait(&io);
340 io.io_op = IO_READ;
341 sccpu_strategy(&io);
342 iowait(&io1);
343 }
344 iowait(&io);
345 }
346
347 write_test()
348 {
349 struct io_req io, io1;
350 register int i;
351
352 bzero(&io, sizeof(io));
353 io.io_unit = test_read_bdev;
354 io.io_op = IO_WRITE;
355 io.io_count = test_read_size;
356 io.io_data = (char*)sccpu_buffer;
357 io1 = io;
358
359 sccpu_strategy(&io);
360 for (i = 1; i < test_read_nreads; i += 2) {
361 io1.io_op = IO_WRITE;
362 sccpu_strategy(&io1);
363 iowait(&io);
364 io.io_op = IO_WRITE;
365 sccpu_strategy(&io);
366 iowait(&io1);
367 }
368 iowait(&io);
369 }
370
371 tur_test()
372 {
373 struct io_req io;
374 register int i;
375 char *a;
376 struct timeval start, stop;
377 spl_t s;
378 target_info_t *tgt;
379
380 bzero(&io, sizeof(io));
381 io.io_unit = test_read_bdev;
382 io.io_data = (char*)&io;/*unused but kernel space*/
383
384 rz_check(io.io_unit, &a, &tgt);
385 s = spl0();
386 start = time;
387 for (i = 0; i < test_read_nreads; i++) {
388 io.io_op = IO_INTERNAL;
389 scsi_test_unit_ready(tgt,&io);
390 }
391 stop = time;
392 splx(s);
393 i = stop.tv_usec - start.tv_usec;
394 if (i < 0) {
395 stop.tv_sec -= 1;
396 i += 1000000;
397 }
398 printf("%d test-unit-ready took %3d sec %d us\n",
399 test_read_nreads,
400 stop.tv_sec - start.tv_sec, i);
401 }
402
403 /*#define MEM_PERF*/
404 #ifdef MEM_PERF
405 int mem_read_size = 1024; /* ints! */
406 int mem_read_nreads = 1000;
407 volatile int *mem_read_address = (volatile int*)0xb0080000;
408 volatile int *mem_write_address = (volatile int*)0xb0081000;
409
410 mem_test(max, which)
411 {
412 int i, ssk, usecs;
413 struct timeval start, stop;
414 int (*fun)(), mwrite_test(), mread_test(), mcopy_test();
415 spl_t s;
416
417 if (max == 0)
418 max = mem_read_nreads;
419
420 switch (which) {
421 case 1: fun = mwrite_test; break;
422 case 2: fun = mcopy_test; break;
423 default:fun = mread_test; break;
424 }
425
426 s = spl0();
427 start = time;
428 for (i = 0; i < max; i++)
429 (*fun)(mem_read_size);
430 stop = time;
431 splx(s);
432
433 usecs = stop.tv_usec - start.tv_usec;
434 if (usecs < 0) {
435 stop.tv_sec -= 1;
436 usecs += 1000000;
437 }
438 printf("Size %d count %d time %3d sec %d us\n",
439 mem_read_size*4, max,
440 stop.tv_sec - start.tv_sec, usecs);
441 }
442
443 mread_test(max)
444 register int max;
445 {
446 register int i;
447 register volatile int *addr = mem_read_address;
448
449 for (i = 0; i < max; i++) {
450 register int j = *addr++;
451 }
452 }
453 mwrite_test(max)
454 register int max;
455 {
456 register int i;
457 register volatile int *addr = mem_read_address;
458
459 for (i = 0; i < max; i++) {
460 *addr++ = i;
461 }
462 }
463
464 mcopy_test(max)
465 register int max;
466 {
467 register volatile int *from = mem_read_address;
468 register volatile int *to = mem_write_address;
469 register volatile int *endaddr;
470
471 endaddr = to + max;
472 while (to < endaddr)
473 *to++ = *from++;
474
475 }
476 #endif /*MEM_PERF*/
477
478 #endif /*PERF*/
479
Cache object: a3b50619cac7c57352c1f12bb4df1867
|