FreeBSD/Linux Kernel Cross Reference
sys/scsi/rz.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993-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.c,v $
29 * Revision 2.19 93/05/15 19:42:33 mrt
30 * machparam.h -> machspl.h
31 *
32 * Revision 2.18 93/05/10 21:22:18 rvb
33 * Removed depend on DEV_BSIZE. Lint.
34 * [93/05/06 10:14:29 af]
35 *
36 * Revision 2.17 93/03/09 10:57:31 danner
37 * rz_check now is officially exported by this module.
38 * [93/03/06 af]
39 *
40 * Revision 2.16 93/01/14 17:55:09 danner
41 * Proper spl typing.
42 * [92/12/01 af]
43 *
44 * Added rz_simple_strategy(), common strategy routine for (most) devices
45 * that do not need to reorder requests.
46 * [92/11/29 af]
47 *
48 * Revision 2.15 92/08/03 17:53:15 jfriedl
49 * removed silly prototypes
50 * [92/08/02 jfriedl]
51 *
52 * Revision 2.14 92/05/21 17:23:17 jfriedl
53 * Cleanup to quiet gcc warnings.
54 * [92/05/16 jfriedl]
55 *
56 * Revision 2.13 92/02/23 22:44:12 elf
57 * Changed the interface of a number of functions not to
58 * require the scsi_softc pointer any longer. It was
59 * mostly unused, now it can be found via tgt->masterno.
60 * [92/02/22 19:31:18 af]
61 *
62 * Revision 2.12 92/01/03 20:44:06 dbg
63 * Added rz_devinfo().
64 * [91/12/26 11:10:59 af]
65 *
66 * Revision 2.11 91/10/09 16:16:57 af
67 * Zero io_error before using the ior.
68 *
69 * Revision 2.10 91/08/24 12:27:43 af
70 * Pass along the ior in open calls.
71 * Removed luna88k specialization, as the device headers have been
72 * rationalized.
73 * [91/08/02 03:51:40 af]
74 *
75 * Revision 2.9 91/07/09 23:22:23 danner
76 * Added gross ifdef luna88k to use <sd.h> instead of <scsi.h>. Will
77 * be fixed as soon as I figure out the configuration tools.
78 * [91/07/09 11:05:28 danner]
79 *
80 * Revision 2.8 91/06/19 11:56:54 rvb
81 * File moved here from mips/PMAX since it is now "MI" code, also
82 * used by Vax3100 and soon -- the omron luna88k.
83 * [91/06/04 rvb]
84 *
85 * Revision 2.7 91/05/14 17:26:11 mrt
86 * Correcting copyright
87 *
88 * Revision 2.6 91/05/13 06:04:14 af
89 * Use a longer timeout on opens (exabytes are so slooooow to
90 * get ready). If we are still rewinding the tape make open
91 * fail. Start watchdog on first open, for those adapters
92 * that need it. Ask for sense data when unit does not
93 * come online quickly enough. On close, invoke anything
94 * target-specific that needs to.
95 * [91/05/12 16:04:29 af]
96 *
97 * Revision 2.5.1.1 91/03/29 17:21:00 af
98 * Use a longer timeout on opens (exabytes are so slooooow to
99 * get ready). If we are still rewinding the tape make open
100 * fail. Start watchdog on first open, for those adapters
101 * that need it. Ask for sense data when unit does not
102 * come online quickly enough. On close, invoke anything
103 * target-specific that needs to.
104 *
105 * Revision 2.5 91/02/05 17:43:37 mrt
106 * Added author notices
107 * [91/02/04 11:16:27 mrt]
108 *
109 * Changed to use new Mach copyright
110 * [91/02/02 12:15:22 mrt]
111 *
112 * Revision 2.4 90/12/20 16:59:59 jeffreyh
113 * Do not use minphys(), we do not need to trim requests.
114 * [90/12/11 af]
115 *
116 * Revision 2.3 90/12/05 23:33:46 af
117 * Cut&retry for requests that exceed the HBA's dma capacity.
118 * [90/12/03 23:32:38 af]
119 *
120 * Revision 2.1.1.1 90/11/01 03:43:31 af
121 * Created.
122 * [90/10/21 af]
123 */
124 /*
125 * File: rz.c
126 * Author: Alessandro Forin, Carnegie Mellon University
127 * Date: 10/90
128 *
129 * Top layer of the SCSI driver: interface with the MI side.
130 */
131
132 /*
133 * This file contains the code that is common to all scsi devices,
134 * operations and/or behaviours specific to certain devices live
135 * in the corresponding rz_mumble files.
136 */
137
138 #include <scsi.h>
139
140 #if (NSCSI>0)
141
142 #include <mach/std_types.h>
143 #include <machine/machspl.h> /* spl definitions */
144 #include <scsi/compat_30.h>
145
146 #ifdef MACH_KERNEL
147 #include <kern/time_out.h>
148 #else /*MACH_KERNEL*/
149 #include <sys/kernel.h> /* for hz */
150
151 static io_req_t getbp();
152 #endif /*MACH_KERNEL*/
153
154 #include <scsi/scsi_defs.h>
155 #include <scsi/rz.h>
156
157
158 boolean_t
159 rz_check(dev, p_sc, p_tgt)
160 int dev;
161 scsi_softc_t **p_sc;
162 target_info_t **p_tgt;
163 {
164 if (rzcontroller(dev) >= NSCSI ||
165 (*p_sc = scsi_softc[rzcontroller(dev)]) == 0)
166 return FALSE;
167
168 *p_tgt = (*p_sc)->target[rzslave(dev)];
169
170 if (!*p_tgt ||
171 !((*p_tgt)->flags&TGT_ALIVE))
172 return FALSE;
173 return TRUE;
174 }
175
176 /*
177 * Open routine
178 *
179 * On tapes and other devices might have to wait a bit for
180 * the unit to come alive. The following patchable variable
181 * takes this into account
182 */
183 int rz_open_timeout = 60;/* seconds */
184
185 int rz_open(dev, mode, ior)
186 int dev;
187 dev_mode_t mode;
188 io_req_t ior;
189 {
190 scsi_softc_t *sc = 0;
191 target_info_t *tgt;
192 scsi_ret_t ret;
193 register int i;
194
195 if (!rz_check(dev, &sc, &tgt)) {
196 /*
197 * Probe it again: might have installed a new device
198 */
199 if (!sc || !scsi_probe(sc, &tgt, rzslave(dev), ior))
200 return D_NO_SUCH_DEVICE;
201 }
202
203 /* tapes do not wait for rewind to complete on close */
204 if (tgt->ior && !(tgt->flags & TGT_ONLINE))
205 return D_WOULD_BLOCK;
206
207 if (scsi_debug)
208 printf("opening %s%d..", (*tgt->dev_ops->driver_name)(TRUE), dev&0xff);
209
210 if (sc->watchdog) {
211 (*sc->watchdog)(tgt->hw_state);
212 sc->watchdog = 0;
213 }
214
215 /*
216 * Bring the unit online, retrying if necessary.
217 * If the target is spinning up we wait for it.
218 */
219 if ( ! (tgt->flags & TGT_ONLINE)) {
220 io_req_t tmp_ior;
221
222 io_req_alloc(tmp_ior,0);
223 tmp_ior->io_next = 0;
224 tmp_ior->io_count = 0;
225
226 for (i = 0; i < rz_open_timeout; i++) {
227
228 tmp_ior->io_op = IO_INTERNAL;
229 tmp_ior->io_error = 0;
230 ret = scsi_test_unit_ready(tgt, tmp_ior);
231
232 if (ret == SCSI_RET_SUCCESS)
233 break;
234
235 if (ret == SCSI_RET_DEVICE_DOWN) {
236 i = rz_open_timeout;
237 break;
238 }
239
240 if (ret == SCSI_RET_NEED_SENSE) {
241
242 tmp_ior->io_op = IO_INTERNAL;
243 tmp_ior->io_count = 0;
244 tmp_ior->io_residual = 0;
245 tgt->ior = tmp_ior;
246 scsi_request_sense(tgt, tmp_ior, 0);
247 iowait(tmp_ior);
248
249 }
250
251 if (i == 5) printf("%s%d: %s\n",
252 (*tgt->dev_ops->driver_name)(TRUE),
253 tgt->target_id,
254 "Waiting to come online..");
255 timeout(wakeup, tgt, hz);
256 await(tgt);
257 }
258
259 /* lock on removable media */
260 if ((i != rz_open_timeout) && (tgt->flags & TGT_REMOVABLE_MEDIA)) {
261 tmp_ior->io_op = IO_INTERNAL;
262 /* too many dont support it. Sigh */
263 tgt->flags |= TGT_OPTIONAL_CMD;
264 (void) scsi_medium_removal( tgt, FALSE, tmp_ior);
265 tgt->flags &= ~TGT_OPTIONAL_CMD;
266 }
267
268 io_req_free(tmp_ior);
269 if (i == rz_open_timeout)
270 return D_DEVICE_DOWN;
271 }
272 /*
273 * Perform anything open-time special on the device
274 */
275 if (tgt->dev_ops->open != SCSI_OPEN_NULL) {
276 ret = (*tgt->dev_ops->open)(tgt, ior);
277 if (ret != SCSI_RET_SUCCESS) {
278 if (scsi_debug) printf("%s%d: open failed x%x\n",
279 (*tgt->dev_ops->driver_name)(TRUE), dev&0xff, ret);
280 return ret;
281 }
282 }
283 tgt->flags |= TGT_ONLINE;
284 ior->io_device->bsize = tgt->block_size;
285 return D_SUCCESS;
286 }
287
288 int rz_close(dev)
289 int dev;
290 {
291 scsi_softc_t *sc;
292 target_info_t *tgt;
293 scsi_ret_t ret;
294
295 if (!rz_check(dev, &sc, &tgt))
296 return D_NO_SUCH_DEVICE;
297
298 if (scsi_debug)
299 printf("closing %s%d..", (*tgt->dev_ops->driver_name)(TRUE), dev&0xff);
300
301 if (tgt->flags & TGT_REMOVABLE_MEDIA) {
302 io_req_t ior;
303
304 io_req_alloc(ior,0);
305 ior->io_next = 0;
306 ior->io_count = 0;
307 ior->io_op = IO_INTERNAL;
308 ior->io_error = 0;
309 /* too many dont support it. Sigh */
310 tgt->flags |= TGT_OPTIONAL_CMD;
311 (void) scsi_medium_removal( tgt, TRUE, ior);
312 tgt->flags &= ~TGT_OPTIONAL_CMD;
313 io_req_free(ior);
314 }
315
316 /*
317 * Perform anything close-time special on the device
318 */
319 if (tgt->dev_ops->close != SCSI_CLOSE_NULL) {
320 ret = (*tgt->dev_ops->close)(tgt);
321 if (ret != SCSI_RET_SUCCESS) {
322 printf("%s%d: close failed x%x\n",
323 (*tgt->dev_ops->driver_name)(TRUE), dev&0xff, ret);
324 }
325 }
326 if (tgt->flags & TGT_REMOVABLE_MEDIA)
327 tgt->flags &= ~TGT_ONLINE;
328
329 return D_SUCCESS;
330 }
331
332 /* our own minphys */
333 void rz_minphys(ior)
334 io_req_t ior;
335 {
336 #ifdef MACH_KERNEL
337 #else /*MACH_KERNEL*/
338 if (ior->io_count > scsi_per_target_virtual)
339 ior->io_count = scsi_per_target_virtual;
340 #endif /*MACH_KERNEL*/
341 }
342
343 int rz_read(dev, ior)
344 int dev;
345 io_req_t ior;
346 {
347 target_info_t *tgt;
348
349 tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
350
351 #ifdef MACH_KERNEL
352 return block_io(tgt->dev_ops->strategy, rz_minphys, ior);
353 #else /*MACH_KERNEL*/
354 return physio(tgt->dev_ops->strategy, getbp(dev), dev, IO_READ, rz_minphys, ior);
355 #endif /*MACH_KERNEL*/
356 }
357
358 int rz_write(dev, ior)
359 int dev;
360 io_req_t ior;
361 {
362 target_info_t *tgt;
363
364 tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
365
366 if (tgt->flags & TGT_READONLY)
367 return D_INVALID_OPERATION;
368
369 #ifdef MACH_KERNEL
370 return block_io(tgt->dev_ops->strategy, rz_minphys, ior);
371 #else /*MACH_KERNEL*/
372 return physio(tgt->dev_ops->strategy, getbp(dev), dev, IO_WRITE, rz_minphys, ior);
373 #endif /*MACH_KERNEL*/
374 }
375
376 int rz_get_status(dev, flavor, status, status_count)
377 int dev;
378 dev_flavor_t flavor;
379 dev_status_t status;
380 natural_t *status_count;
381 {
382 target_info_t *tgt;
383
384 tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
385
386 if (scsi_debug)
387 printf("rz_get_status: x%x x%x x%x x%x\n",
388 dev, flavor, status, *status_count);
389 return (*tgt->dev_ops->get_status)(dev, tgt, flavor, status, status_count);
390 }
391
392 int rz_set_status(dev, flavor, status, status_count)
393 int dev;
394 dev_flavor_t flavor;
395 dev_status_t status;
396 natural_t status_count;
397 {
398 target_info_t *tgt;
399
400 tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
401
402 if (scsi_debug)
403 printf("rz_set_status: x%x x%x x%x x%x\n",
404 dev, flavor, status, status_count);
405 return (*tgt->dev_ops->set_status)(dev, tgt, flavor, status, status_count);
406 }
407
408 /*
409 * Routine to return information to kernel.
410 */
411 int
412 rz_devinfo(dev, flavor, info)
413 int dev;
414 int flavor;
415 char *info;
416 {
417 register int result;
418
419 result = D_SUCCESS;
420
421 switch (flavor) {
422 /* Caller stupidity, should use device->bsize instead */
423 case D_INFO_BLOCK_SIZE:
424 *((int *) info) = scsi_softc[rzcontroller(dev)]->
425 target[rzslave(dev)]->block_size;
426 break;
427 default:
428 result = D_INVALID_OPERATION;
429 }
430
431 return(result);
432 }
433
434 void
435 rz_simpleq_strategy(ior, start)
436 io_req_t ior;
437 void (*start)();
438 {
439 target_info_t *tgt;
440 register scsi_softc_t *sc;
441 scsi_ret_t ret;
442 register int i = ior->io_unit;
443 io_req_t head, tail;
444 spl_t s;
445
446 sc = scsi_softc[rzcontroller(i)];
447 tgt = sc->target[rzslave(i)];
448
449 ior->io_next = 0;
450 ior->io_prev = 0;
451
452 s = splbio();
453 simple_lock(&tgt->target_lock);
454 if (head = tgt->ior) {
455 /* Queue it up at the end of the list */
456 if (tail = head->io_prev)
457 tail->io_next = ior;
458 else
459 head->io_next = ior;
460 head->io_prev = ior; /* tail pointer */
461 simple_unlock(&tgt->target_lock);
462 } else {
463 /* Was empty, start operation */
464 tgt->ior = ior;
465 simple_unlock(&tgt->target_lock);
466 (*start)( tgt, FALSE);
467 }
468 splx(s);
469 }
470 #ifdef MACH_KERNEL
471 #else /*MACH_KERNEL*/
472
473 rz_strategy(ior)
474 io_req_t ior;
475 {
476 target_info_t *tgt;
477 register int dev = ior->io_unit;
478
479 tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
480
481 return (*tgt->dev_ops->strategy)(ior);
482 }
483
484 #include <sys/ioctl.h>
485
486 #define IOCPARM_SIZE(c) (((c)>>16)&IOCPARM_MASK)
487 #define IOC_WDSIZE(s) ((IOCPARM_SIZE(s))>>2)
488
489 rz_ioctl(dev, cmd, data, flag)
490 {
491 io_return_t error;
492 unsigned int count;
493
494 count = IOC_WDSIZE(cmd);
495 if (cmd & (IOC_VOID|IOC_IN)) {
496 error = rz_set_status(dev, cmd, (dev_status_t)data, count);
497 if (error)
498 return (error);
499 }
500 if (cmd & IOC_OUT) {
501 error = rz_get_status(dev, cmd, (dev_status_t *)data, &count);
502 if (error)
503 return (error);
504 }
505 return (0);
506 }
507
508 /* This is a very simple-minded config,
509 * assumes we have << 8 disks per bus */
510 #define NBUF (NSCSI*8)
511 struct io_req rz_buffers[NBUF];
512
513 static io_req_t
514 getbp(dev)
515 {
516 io_req_t ior;
517 int hash = minor(dev) >> 3;
518
519 ior = &rz_buffers[hash];
520 if (ior->io_op & IO_BUSY) {
521 register io_req_t ior;
522 for (ior = rz_buffers; ior < &rz_buffers[NBUF]; ior++)
523 if ((ior->io_op & IO_BUSY) == 0)
524 return ior;
525
526 }
527 return ior;
528 }
529
530 /*
531 * This ugliness is only needed because of the
532 * way the minor is encoded for tapes.
533 */
534 tz_open(dev, mode, ior)
535 int dev;
536 dev_mode_t mode;
537 io_req_t ior;
538 {
539 io_return_t error;
540
541 error = rz_open(TAPE_UNIT(dev), mode, ior);
542 if(error)
543 return error;
544 if (TAPE_REWINDS(dev)) {
545 scsi_softc_t *sc;
546 target_info_t *tgt;
547
548 rz_check(TAPE_UNIT(dev), &sc, &tgt);
549 tgt->flags |= TGT_REWIND_ON_CLOSE;
550 }
551 return 0;
552 }
553
554 tz_close(dev) { return rz_close(TAPE_UNIT(dev));}
555 tz_read(dev, ior) { return rz_read(TAPE_UNIT(dev), ior);}
556 tz_write(dev, ior) { return rz_write(TAPE_UNIT(dev), ior);}
557 tz_ioctl(dev, cmd, data, flag) { return rz_ioctl(TAPE_UNIT(dev), cmd, data, flag);}
558
559 #endif /*MACH_KERNEL*/
560
561 #endif (NSCSI>0)
Cache object: 3955b881b0f99d6b779ed69844fb9a0b
|