|
|
1.1 root 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 [email protected]
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: * File: rz.c
28: * Author: Alessandro Forin, Carnegie Mellon University
29: * Date: 10/90
30: *
31: * Top layer of the SCSI driver: interface with the MI side.
32: */
33:
34: /*
35: * This file contains the code that is common to all scsi devices,
36: * operations and/or behaviours specific to certain devices live
37: * in the corresponding rz_mumble files.
38: */
39:
40: #include <scsi.h>
41:
42: #if (NSCSI>0)
43:
44: #include <mach/std_types.h>
45: #include <machine/machspl.h> /* spl definitions */
46: #include <scsi/compat_30.h>
47:
48: #ifdef MACH_KERNEL
49: #include <kern/time_out.h>
50: #else /*MACH_KERNEL*/
51: #include <sys/kernel.h> /* for hz */
52:
53: static io_req_t getbp();
54: #endif /*MACH_KERNEL*/
55:
56: #include <scsi/scsi_defs.h>
57: #include <scsi/rz.h>
58:
59:
60: boolean_t
61: rz_check(dev, p_sc, p_tgt)
62: int dev;
63: scsi_softc_t **p_sc;
64: target_info_t **p_tgt;
65: {
66: if (rzcontroller(dev) >= NSCSI ||
67: (*p_sc = scsi_softc[rzcontroller(dev)]) == 0)
68: return FALSE;
69:
70: *p_tgt = (*p_sc)->target[rzslave(dev)];
71:
72: if (!*p_tgt ||
73: !((*p_tgt)->flags&TGT_ALIVE))
74: return FALSE;
75: return TRUE;
76: }
77:
78: /*
79: * Open routine
80: *
81: * On tapes and other devices might have to wait a bit for
82: * the unit to come alive. The following patchable variable
83: * takes this into account
84: */
85: int rz_open_timeout = 60;/* seconds */
86:
87: int rz_open(dev, mode, ior)
88: int dev;
89: dev_mode_t mode;
90: io_req_t ior;
91: {
92: scsi_softc_t *sc = 0;
93: target_info_t *tgt;
94: scsi_ret_t ret;
95: register int i;
96:
97: if (!rz_check(dev, &sc, &tgt)) {
98: /*
99: * Probe it again: might have installed a new device
100: */
101: if (!sc || !scsi_probe(sc, &tgt, rzslave(dev), ior))
102: return D_NO_SUCH_DEVICE;
103: }
104:
105: /* tapes do not wait for rewind to complete on close */
106: if (tgt->ior && !(tgt->flags & TGT_ONLINE))
107: return D_WOULD_BLOCK;
108:
109: if (scsi_debug)
110: printf("opening %s%d..", (*tgt->dev_ops->driver_name)(TRUE), dev&0xff);
111:
112: if (sc->watchdog) {
113: (*sc->watchdog)(tgt->hw_state);
114: sc->watchdog = 0;
115: }
116:
117: /*
118: * Bring the unit online, retrying if necessary.
119: * If the target is spinning up we wait for it.
120: */
121: if ( ! (tgt->flags & TGT_ONLINE)) {
122: io_req_t tmp_ior;
123:
124: io_req_alloc(tmp_ior,0);
125: tmp_ior->io_next = 0;
126: tmp_ior->io_count = 0;
127:
128: for (i = 0; i < rz_open_timeout; i++) {
129:
130: tmp_ior->io_op = IO_INTERNAL;
131: tmp_ior->io_error = 0;
132: ret = scsi_test_unit_ready(tgt, tmp_ior);
133:
134: if (ret == SCSI_RET_SUCCESS)
135: break;
136:
137: if (ret == SCSI_RET_DEVICE_DOWN) {
138: i = rz_open_timeout;
139: break;
140: }
141:
142: if (ret == SCSI_RET_NEED_SENSE) {
143:
144: tmp_ior->io_op = IO_INTERNAL;
145: tmp_ior->io_count = 0;
146: tmp_ior->io_residual = 0;
147: tgt->ior = tmp_ior;
148: scsi_request_sense(tgt, tmp_ior, 0);
149: iowait(tmp_ior);
150:
151: }
152:
153: if (i == 5) printf("%s%d: %s\n",
154: (*tgt->dev_ops->driver_name)(TRUE),
155: tgt->target_id,
156: "Waiting to come online..");
157: timeout(wakeup, tgt, hz);
158: await(tgt);
159: }
160:
161: /* lock on removable media */
162: if ((i != rz_open_timeout) && (tgt->flags & TGT_REMOVABLE_MEDIA)) {
163: tmp_ior->io_op = IO_INTERNAL;
164: /* too many dont support it. Sigh */
165: tgt->flags |= TGT_OPTIONAL_CMD;
166: (void) scsi_medium_removal( tgt, FALSE, tmp_ior);
167: tgt->flags &= ~TGT_OPTIONAL_CMD;
168: }
169:
170: io_req_free(tmp_ior);
171: if (i == rz_open_timeout)
172: return D_DEVICE_DOWN;
173: }
174: /*
175: * Perform anything open-time special on the device
176: */
177: if (tgt->dev_ops->open != SCSI_OPEN_NULL) {
178: ret = (*tgt->dev_ops->open)(tgt, ior);
179: if (ret != SCSI_RET_SUCCESS) {
180: if (scsi_debug) printf("%s%d: open failed x%x\n",
181: (*tgt->dev_ops->driver_name)(TRUE), dev&0xff, ret);
182: return ret;
183: }
184: }
185: tgt->flags |= TGT_ONLINE;
186: ior->io_device->bsize = tgt->block_size;
187: return D_SUCCESS;
188: }
189:
190: int rz_close(dev)
191: int dev;
192: {
193: scsi_softc_t *sc;
194: target_info_t *tgt;
195: scsi_ret_t ret;
196:
197: if (!rz_check(dev, &sc, &tgt))
198: return D_NO_SUCH_DEVICE;
199:
200: if (scsi_debug)
201: printf("closing %s%d..", (*tgt->dev_ops->driver_name)(TRUE), dev&0xff);
202:
203: if (tgt->flags & TGT_REMOVABLE_MEDIA) {
204: io_req_t ior;
205:
206: io_req_alloc(ior,0);
207: ior->io_next = 0;
208: ior->io_count = 0;
209: ior->io_op = IO_INTERNAL;
210: ior->io_error = 0;
211: /* too many dont support it. Sigh */
212: tgt->flags |= TGT_OPTIONAL_CMD;
213: (void) scsi_medium_removal( tgt, TRUE, ior);
214: tgt->flags &= ~TGT_OPTIONAL_CMD;
215: io_req_free(ior);
216: }
217:
218: /*
219: * Perform anything close-time special on the device
220: */
221: if (tgt->dev_ops->close != SCSI_CLOSE_NULL) {
222: ret = (*tgt->dev_ops->close)(tgt);
223: if (ret != SCSI_RET_SUCCESS) {
224: printf("%s%d: close failed x%x\n",
225: (*tgt->dev_ops->driver_name)(TRUE), dev&0xff, ret);
226: }
227: }
228: if (tgt->flags & TGT_REMOVABLE_MEDIA)
229: tgt->flags &= ~TGT_ONLINE;
230:
231: return D_SUCCESS;
232: }
233:
234: /* our own minphys */
235: void rz_minphys(ior)
236: io_req_t ior;
237: {
238: #ifdef MACH_KERNEL
239: #else /*MACH_KERNEL*/
240: if (ior->io_count > scsi_per_target_virtual)
241: ior->io_count = scsi_per_target_virtual;
242: #endif /*MACH_KERNEL*/
243: }
244:
245: int rz_read(dev, ior)
246: int dev;
247: io_req_t ior;
248: {
249: target_info_t *tgt;
250:
251: tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
252:
253: #ifdef MACH_KERNEL
254: return block_io(tgt->dev_ops->strategy, rz_minphys, ior);
255: #else /*MACH_KERNEL*/
256: return physio(tgt->dev_ops->strategy, getbp(dev), dev, IO_READ, rz_minphys, ior);
257: #endif /*MACH_KERNEL*/
258: }
259:
260: int rz_write(dev, ior)
261: int dev;
262: io_req_t ior;
263: {
264: target_info_t *tgt;
265:
266: tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
267:
268: if (tgt->flags & TGT_READONLY)
269: return D_INVALID_OPERATION;
270:
271: #ifdef MACH_KERNEL
272: return block_io(tgt->dev_ops->strategy, rz_minphys, ior);
273: #else /*MACH_KERNEL*/
274: return physio(tgt->dev_ops->strategy, getbp(dev), dev, IO_WRITE, rz_minphys, ior);
275: #endif /*MACH_KERNEL*/
276: }
277:
278: int rz_get_status(dev, flavor, status, status_count)
279: int dev;
280: dev_flavor_t flavor;
281: dev_status_t status;
282: natural_t *status_count;
283: {
284: target_info_t *tgt;
285:
286: tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
287:
288: if (scsi_debug)
289: printf("rz_get_status: x%x x%x x%x x%x\n",
290: dev, flavor, status, *status_count);
291: return (*tgt->dev_ops->get_status)(dev, tgt, flavor, status, status_count);
292: }
293:
294: int rz_set_status(dev, flavor, status, status_count)
295: int dev;
296: dev_flavor_t flavor;
297: dev_status_t status;
298: natural_t status_count;
299: {
300: target_info_t *tgt;
301:
302: tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
303:
304: if (scsi_debug)
305: printf("rz_set_status: x%x x%x x%x x%x\n",
306: dev, flavor, status, status_count);
307: return (*tgt->dev_ops->set_status)(dev, tgt, flavor, status, status_count);
308: }
309:
310: /*
311: * Routine to return information to kernel.
312: */
313: int
314: rz_devinfo(dev, flavor, info)
315: int dev;
316: int flavor;
317: char *info;
318: {
319: register int result;
320:
321: result = D_SUCCESS;
322:
323: switch (flavor) {
324: /* Caller stupidity, should use device->bsize instead */
325: case D_INFO_BLOCK_SIZE:
326: *((int *) info) = scsi_softc[rzcontroller(dev)]->
327: target[rzslave(dev)]->block_size;
328: break;
329: default:
330: result = D_INVALID_OPERATION;
331: }
332:
333: return(result);
334: }
335:
336: void
337: rz_simpleq_strategy(ior, start)
338: io_req_t ior;
339: void (*start)();
340: {
341: target_info_t *tgt;
342: register scsi_softc_t *sc;
343: scsi_ret_t ret;
344: register int i = ior->io_unit;
345: io_req_t head, tail;
346: spl_t s;
347:
348: sc = scsi_softc[rzcontroller(i)];
349: tgt = sc->target[rzslave(i)];
350:
351: ior->io_next = 0;
352: ior->io_prev = 0;
353:
354: s = splbio();
355: simple_lock(&tgt->target_lock);
356: if (head = tgt->ior) {
357: /* Queue it up at the end of the list */
358: if (tail = head->io_prev)
359: tail->io_next = ior;
360: else
361: head->io_next = ior;
362: head->io_prev = ior; /* tail pointer */
363: simple_unlock(&tgt->target_lock);
364: } else {
365: /* Was empty, start operation */
366: tgt->ior = ior;
367: simple_unlock(&tgt->target_lock);
368: (*start)( tgt, FALSE);
369: }
370: splx(s);
371: }
372: #ifdef MACH_KERNEL
373: #else /*MACH_KERNEL*/
374:
375: rz_strategy(ior)
376: io_req_t ior;
377: {
378: target_info_t *tgt;
379: register int dev = ior->io_unit;
380:
381: tgt = scsi_softc[rzcontroller(dev)]->target[rzslave(dev)];
382:
383: return (*tgt->dev_ops->strategy)(ior);
384: }
385:
386:
387: #define IOCPARM_SIZE(c) (((c)>>16)&IOCPARM_MASK)
388: #define IOC_WDSIZE(s) ((IOCPARM_SIZE(s))>>2)
389:
390: rz_ioctl(dev, cmd, data, flag)
391: {
392: io_return_t error;
393: unsigned int count;
394:
395: count = IOC_WDSIZE(cmd);
396: if (cmd & (IOC_VOID|IOC_IN)) {
397: error = rz_set_status(dev, cmd, (dev_status_t)data, count);
398: if (error)
399: return (error);
400: }
401: if (cmd & IOC_OUT) {
402: error = rz_get_status(dev, cmd, (dev_status_t *)data, &count);
403: if (error)
404: return (error);
405: }
406: return (0);
407: }
408:
409: /* This is a very simple-minded config,
410: * assumes we have << 8 disks per bus */
411: #define NBUF (NSCSI*8)
412: struct io_req rz_buffers[NBUF];
413:
414: static io_req_t
415: getbp(dev)
416: {
417: io_req_t ior;
418: int hash = minor(dev) >> 3;
419:
420: ior = &rz_buffers[hash];
421: if (ior->io_op & IO_BUSY) {
422: register io_req_t ior;
423: for (ior = rz_buffers; ior < &rz_buffers[NBUF]; ior++)
424: if ((ior->io_op & IO_BUSY) == 0)
425: return ior;
426:
427: }
428: return ior;
429: }
430:
431: /*
432: * This ugliness is only needed because of the
433: * way the minor is encoded for tapes.
434: */
435: tz_open(dev, mode, ior)
436: int dev;
437: dev_mode_t mode;
438: io_req_t ior;
439: {
440: io_return_t error;
441:
442: error = rz_open(TAPE_UNIT(dev), mode, ior);
443: if(error)
444: return error;
445: if (TAPE_REWINDS(dev)) {
446: scsi_softc_t *sc;
447: target_info_t *tgt;
448:
449: rz_check(TAPE_UNIT(dev), &sc, &tgt);
450: tgt->flags |= TGT_REWIND_ON_CLOSE;
451: }
452: return 0;
453: }
454:
455: tz_close(dev) { return rz_close(TAPE_UNIT(dev));}
456: tz_read(dev, ior) { return rz_read(TAPE_UNIT(dev), ior);}
457: tz_write(dev, ior) { return rz_write(TAPE_UNIT(dev), ior);}
458: tz_ioctl(dev, cmd, data, flag) { return rz_ioctl(TAPE_UNIT(dev), cmd, data, flag);}
459:
460: #endif /*MACH_KERNEL*/
461:
462: #endif (NSCSI>0)
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.