|
|
1.1 root 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 [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_disk.c
28: * Author: Alessandro Forin, Carnegie Mellon University
29: * Date: 10/90
30: *
31: * Top layer of the SCSI driver: interface with the MI.
32: * This file contains operations specific to disk-like devices.
33: *
34: * Modified by Kevin T. Van Maren to use a common partition code
35: * with the ide driver, and support 'slices'.
36: */
37:
38:
39: #include <scsi/scsi.h>
40: #if (NSCSI > 0)
41:
42: #include <device/buf.h>
43: #include <device/disk_status.h>
44: #include <device/device_types.h>
45: #include <device/param.h>
46: #include <device/errno.h>
47:
48: #include <kern/time_out.h>
49: #include <machine/machspl.h> /* spl definitions */
50: #include <mach/std_types.h>
51: #include <platforms.h>
52:
53: #include <scsi/compat_30.h>
54: #include <scsi/scsi.h>
55: #include <scsi/scsi_defs.h>
56: #include <scsi/rz.h>
57: #include <scsi/rz_labels.h>
58:
59: #ifdef MACH_KERNEL
60: #else /*MACH_KERNEL*/
61: #include <sys/kernel.h> /* for hz */
62: #endif /*MACH_KERNEL*/
63:
64: #include <sys/types.h>
65: #include <sys/ioctl.h>
66: #include "vm_param.h"
67: #include <vm/vm_kern.h>
68: #include <vm/pmap.h>
69:
70: extern void scdisk_read(), scdisk_write(),
71: scsi_long_read(), scsi_long_write();
72:
73: void scdisk_start(); /* forwards */
74: void scdisk_start_rw();
75: unsigned dkcksum();
76:
77: #if 0
78: struct diskpart scsi_array[8*64];
79: #endif 0
80:
81:
82: /* THIS IS THE BOTTOM LAYER FOR THE SCSI PARTITION CODE */
83: typedef struct scsi_driver_info {
84: target_info_t *tgt;
85: io_req_t ior;
86: void (*readfun)();
87: int sectorsize;
88: } scsi_driver_info;
89:
90: int scsi_read_fun(scsi_driver_info *param, int sectornum, void *buff)
91: {
92: char *psave;
93: int result = TRUE; /* SUCCESS */
94: psave=param->ior->io_data; /* is this necessary ? */
95:
96: param->ior->io_data=buff;
97: param->ior->io_count = param->sectorsize;
98: param->ior->io_op = IO_READ;
99: param->ior->io_error = 0;
100: param->tgt->ior = param->ior;
101:
102: (*param->readfun)( param->tgt, sectornum, param->ior);
103: iowait(param->ior);
104:
105: param->ior->io_data=psave; /* restore the io_data pointer ?? */
106: return(result);
107: }
108:
109:
110:
111: /*
112: * Specialized side of the open routine for disks
113: */
114: scsi_ret_t scdisk_open(tgt, req)
115: target_info_t *tgt;
116: io_req_t req;
117: {
118: register int i, dev_bsize;
119: scsi_ret_t ret = /* SCSI_RET_SUCCESS; */ -1;
120: unsigned int disk_size, secs_per_cyl, sector_size;
121: scsi_rcap_data_t *cap;
122: struct disklabel *label;
123: io_req_t ior;
124: void (*readfun)() = scdisk_read;
125: char *data = (char *)0;
126:
127: int numpart;
128:
129: scsi_driver_info scsi_info;
130: char drive_name[10]; /* used for disklabel strings */
131:
132: if (tgt->flags & TGT_ONLINE)
133: return SCSI_RET_SUCCESS;
134:
135: /*
136: * Dummy ior for proper sync purposes
137: */
138: io_req_alloc(ior,0);
139: ior->io_next = 0;
140: ior->io_count = 0;
141:
142: /*
143: * Set the LBN to DEV_BSIZE with a MODE SELECT.
144: * If this fails we try a couple other tricks.
145: */
146: dev_bsize = 0;
147: for (i = 0; i < 5; i++) {
148: ior->io_op = IO_INTERNAL;
149: ior->io_error = 0;
150: ret = scdisk_mode_select(tgt, DEV_BSIZE, ior, 0, 0, 0);
151: if (ret == SCSI_RET_SUCCESS) {
152: dev_bsize = DEV_BSIZE;
153: break;
154: }
155: if (ret == SCSI_RET_RETRY) {
156: timeout(wakeup, tgt, 2*hz);
157: await(tgt);
158: }
159: if (ret == SCSI_RET_DEVICE_DOWN)
160: goto done;
161: }
162: #if 0
163: if (ret != SCSI_RET_SUCCESS) {
164: scsi_error( tgt, SCSI_ERR_MSEL, ret, 0);
165: ret = D_INVALID_SIZE;
166: goto done;
167: }
168: #endif
169: /*
170: * Do a READ CAPACITY to get max size. Check LBN too.
171: */
172: for (i = 0; i < 5; i++) {
173: ior->io_op = IO_INTERNAL;
174: ior->io_error = 0;
175: ret = scsi_read_capacity(tgt, 0, ior);
176: if (ret == SCSI_RET_SUCCESS)
177: break;
178: }
179: if (ret == SCSI_RET_SUCCESS) {
180: int val;
181:
182: cap = (scsi_rcap_data_t*) tgt->cmd_ptr;
183: disk_size = (cap->lba1<<24) |
184: (cap->lba2<<16) |
185: (cap->lba3<< 8) |
186: cap->lba4;
187: if (scsi_debug)
188: printf("rz%d holds %d blocks\n", tgt->unit_no, disk_size);
189: val = (cap->blen1<<24) |
190: (cap->blen2<<16) |
191: (cap->blen3<<8 ) |
192: cap->blen4;
193: if (dev_bsize == 0)
194: dev_bsize = val;
195: else
196: if (val != dev_bsize) panic("read capacity bad");
197:
198: if (disk_size > SCSI_CMD_READ_MAX_LBA)
199: tgt->flags |= TGT_BIG;
200:
201: } else {
202: printf("Unknown disk capacity??\n");
203: disk_size = -1;
204: }
205: /*
206: * Mandatory long-form commands ?
207: */
208: if (BGET(scsi_use_long_form,(unsigned char)tgt->masterno,tgt->target_id))
209: tgt->flags |= TGT_BIG;
210: if (tgt->flags & TGT_BIG)
211: readfun = scsi_long_read;
212:
213: /*
214: * Some CDROMS truly dislike 512 as LBN.
215: * Use a MODE_SENSE to cover for this case.
216: */
217: if (dev_bsize == 0) {
218: scsi_mode_sense_data_t *m;
219:
220: ior->io_op = IO_INTERNAL;
221: ior->io_error = 0;
222: ret = scsi_mode_sense(tgt, 0/*pagecode*/, 32/*?*/, ior);
223: if (ret == SCSI_RET_SUCCESS) {
224: m = (scsi_mode_sense_data_t *) tgt->cmd_ptr;
225: dev_bsize =
226: m->bdesc[0].blen_msb << 16 |
227: m->bdesc[0].blen << 8 |
228: m->bdesc[0].blen_lsb;
229: }
230: }
231:
232: /*
233: * Find out about the phys disk geometry -- scsi specific
234: */
235:
236: ior->io_op = IO_INTERNAL;
237: ior->io_error = 0;
238: ret = scsi_read_capacity( tgt, 1, ior);
239: if (ret == SCSI_RET_SUCCESS) {
240: cap = (scsi_rcap_data_t*) tgt->cmd_ptr;
241: secs_per_cyl = (cap->lba1<<24) | (cap->lba2<<16) |
242: (cap->lba3<< 8) | cap->lba4;
243: secs_per_cyl += 1;
244: sector_size = (cap->blen1<<24) | (cap->blen2<<16) |
245: (cap->blen3<<8 ) | cap->blen4;
246: } else {
247: sector_size = dev_bsize ? dev_bsize : DEV_BSIZE;
248: secs_per_cyl = disk_size;
249: }
250: if (dev_bsize == 0)
251: dev_bsize = sector_size;
252:
253: if (scsi_debug)
254: printf("rz%d: %d sect/cyl %d bytes/sec\n", tgt->unit_no,
255: secs_per_cyl, sector_size);
256:
257: /*
258: * At this point, one way or other, we are committed to
259: * a given disk capacity and sector size.
260: */
261: tgt->block_size = dev_bsize;
262:
263: /*
264: * Get partition table off pack
265: */
266:
267: #ifdef MACH_KERNEL
268: ior->io_data = (char *)kalloc(sector_size);
269: #endif /*MACH_KERNEL*/
270:
271: scsi_info.tgt=tgt;
272: scsi_info.ior=ior;
273: scsi_info.readfun=readfun;
274: scsi_info.sectorsize=sector_size;
275:
276: /* label has NOT been allocated space yet! set to the tgt disklabel */
277: label=&scsi_info.tgt->dev_info.disk.l;
278:
279: sprintf(drive_name, "sd%d:", tgt->unit_no);
280:
281: if (scsi_debug)
282: printf("Using bogus geometry: 32 sectors/track, 64 heads\n");
283:
284: fudge_bsd_label(label, DTYPE_SCSI, disk_size /* /(32*64)*/ ,
285: 64, 32, sector_size, 8);
286:
287: numpart=get_only_partition(&scsi_info, (*scsi_read_fun),
288: tgt->dev_info.disk.scsi_array, MAX_SCSI_PARTS, disk_size, drive_name);
289:
290: printf("%s %d partitions found\n",drive_name,numpart);
291:
292: ret=SCSI_RET_SUCCESS; /* if 0, return SCSI_RET_SUCCESS */
293:
294:
295: done:
296: io_req_free(ior);
297:
298: return(ret);
299: }
300:
301:
302: /*
303: * Disk strategy routine
304: */
305: int scdisk_strategy(ior)
306: register io_req_t ior;
307: {
308: target_info_t *tgt;
309: register scsi_softc_t *sc;
310: register int i = ior->io_unit, part;
311: register unsigned rec, max;
312: spl_t s;
313: struct diskpart *label;
314:
315: sc = scsi_softc[rzcontroller(i)];
316: tgt = sc->target[rzslave(i)];
317: part = rzpartition(i);
318:
319: /*
320: * Validate request
321: */
322:
323: /* readonly ? */
324: if ((tgt->flags & TGT_READONLY) &&
325: (ior->io_op & (IO_READ|IO_INTERNAL) == 0)) {
326: ior->io_error = D_READ_ONLY;
327: ior->io_op |= IO_ERROR;
328: ior->io_residual = ior->io_count;
329: iodone(ior);
330: return ior->io_error;
331: }
332:
333: rec = ior->io_recnum;
334:
335: label=lookup_part(tgt->dev_info.disk.scsi_array, part);
336: if (!label) {
337: if (scsi_debug)
338: printf("sc strategy -- bad partition\n");
339: ior->io_error = D_INVALID_SIZE;
340: ior->io_op |= IO_ERROR;
341: ior->io_residual = ior->io_count;
342: iodone(ior);
343: return ior->io_error;
344: }
345: else max=label->size;
346: if (max == -1) /* what about 0? */
347: max = tgt->dev_info.disk.l.d_secperunit -
348:
349: label->start;
350:
351: i = (ior->io_count + tgt->block_size - 1) / tgt->block_size;
352: if (((rec + i) > max) || (ior->io_count < 0) ||
353: #if later
354: ((rec <= LABELSECTOR) && ((tgt->flags & TGT_WRITE_LABEL) == 0))
355: #else
356: FALSE
357: #endif
358: ) {
359: ior->io_error = D_INVALID_SIZE;
360: ior->io_op |= IO_ERROR;
361: ior->io_residual = ior->io_count;
362: iodone(ior);
363: return ior->io_error;
364: }
365: /*
366: * Find location on disk: secno and cyl (for disksort)
367: */
368: rec += label->start;
369: ior->io_residual = rec / tgt->dev_info.disk.l.d_secpercyl;
370:
371: /*
372: * Enqueue operation
373: */
374: s = splbio();
375: simple_lock(&tgt->target_lock);
376: if (tgt->ior) {
377: disksort(tgt->ior, ior);
378: simple_unlock(&tgt->target_lock);
379: splx(s);
380: } else {
381: ior->io_next = 0;
382: tgt->ior = ior;
383: simple_unlock(&tgt->target_lock);
384: splx(s);
385:
386: scdisk_start(tgt,FALSE);
387: }
388:
389: return D_SUCCESS;
390: }
391:
392: /*#define CHECKSUM*/
393: #ifdef CHECKSUM
394: int max_checksum_size = 0x2000;
395: #endif CHECKSUM
396:
397: /*
398: * Start/completion routine for disks
399: */
400: void scdisk_start(tgt, done)
401: target_info_t *tgt;
402: boolean_t done;
403: {
404: register io_req_t ior = tgt->ior;
405: register unsigned part;
406: #ifdef CHECKSUM
407: register unsigned secno;
408: #endif
409: struct diskpart *label;
410:
411: if (ior == 0)
412: return;
413:
414: if (tgt->flags & TGT_BBR_ACTIVE)
415: {
416: scdisk_bbr_start(tgt, done);
417: return;
418: }
419:
420: if (done) {
421: register unsigned int xferred;
422: unsigned int max_dma_data;
423:
424: max_dma_data = scsi_softc[(unsigned char)tgt->masterno]->max_dma_data;
425: /* see if we must retry */
426: if ((tgt->done == SCSI_RET_RETRY) &&
427: ((ior->io_op & IO_INTERNAL) == 0)) {
428: delay(1000000);/*XXX*/
429: goto start;
430: } else
431: /* got a bus reset ? pifff.. */
432: if ((tgt->done == (SCSI_RET_ABORTED|SCSI_RET_RETRY)) &&
433: ((ior->io_op & IO_INTERNAL) == 0)) {
434: if (xferred = ior->io_residual) {
435: ior->io_data -= xferred;
436: ior->io_count += xferred;
437: ior->io_recnum -= xferred / tgt->block_size;
438: ior->io_residual = 0;
439: }
440: goto start;
441: } else
442: /*
443: * Quickly check for errors: if anything goes wrong
444: * we do a request sense, see if that is what we did.
445: */
446: if (tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) {
447: scsi_sense_data_t *sns;
448: unsigned int blockno;
449: char *outcome;
450:
451: ior->io_op = ior->io_temporary;
452:
453: sns = (scsi_sense_data_t *)tgt->cmd_ptr;
454: if (sns->addr_valid)
455: blockno = sns->u.xtended.info0 << 24 |
456: sns->u.xtended.info1 << 16 |
457: sns->u.xtended.info2 << 8 |
458: sns->u.xtended.info3;
459: else {
460: part = rzpartition(ior->io_unit);
461: label = lookup_part(tgt->dev_info.disk.scsi_array, part);
462: blockno = label->start;
463: blockno += ior->io_recnum;
464: if (!label) blockno=-1;
465: }
466:
467: if (scsi_check_sense_data(tgt, sns)) {
468: ior->io_error = 0;
469: if ((tgt->done == SCSI_RET_RETRY) &&
470: ((ior->io_op & IO_INTERNAL) == 0)) {
471: delay(1000000);/*XXX*/
472: goto start;
473: }
474: outcome = "Recovered";
475: } else {
476: outcome = "Unrecoverable";
477: ior->io_error = D_IO_ERROR;
478: ior->io_op |= IO_ERROR;
479: }
480: if ((tgt->flags & TGT_OPTIONAL_CMD) == 0) {
481: printf("%s Error, rz%d: %s%s%d\n", outcome,
482: tgt->target_id + (tgt->masterno * 8),
483: (ior->io_op & IO_READ) ? "Read" :
484: ((ior->io_op & IO_INTERNAL) ? "(command)" : "Write"),
485: " disk error, phys block no. ", blockno);
486:
487: scsi_print_sense_data(sns);
488:
489: /*
490: * On fatal read/write errors try replacing the bad block
491: * The bbr routine will return TRUE iff it took control
492: * over the target for all subsequent operations. In this
493: * event, the queue of requests is effectively frozen.
494: */
495: if (ior->io_error &&
496: ((sns->error_class == SCSI_SNS_XTENDED_SENSE_DATA) &&
497: ((sns->u.xtended.sense_key == SCSI_SNS_HW_ERR) ||
498: (sns->u.xtended.sense_key == SCSI_SNS_MEDIUM_ERR))) &&
499: scdisk_bad_block_repl(tgt, blockno))
500: return;
501: }
502: }
503:
504: /*
505: * See if we had errors
506: */
507: else if (tgt->done != SCSI_RET_SUCCESS) {
508:
509: if (tgt->done == SCSI_RET_NEED_SENSE) {
510:
511: ior->io_temporary = ior->io_op;
512: ior->io_op = IO_INTERNAL;
513: scsi_request_sense(tgt, ior, 0);
514: return;
515:
516: } else if (tgt->done == SCSI_RET_DEVICE_DOWN) {
517: ior->io_error = D_DEVICE_DOWN;
518: ior->io_op |= IO_ERROR;
519: } else {
520: printf("%s%x\n", "?rz_disk Disk error, ret=x", tgt->done);
521: ior->io_error = D_IO_ERROR;
522: ior->io_op |= IO_ERROR;
523: }
524: }
525: /*
526: * No errors.
527: * See if we requested more than the max
528: * (We use io_residual in a flip-side way here)
529: */
530: else if (ior->io_count > (xferred = max_dma_data)) {
531: ior->io_residual += xferred;
532: ior->io_count -= xferred;
533: ior->io_data += xferred;
534: ior->io_recnum += xferred / tgt->block_size;
535: goto start;
536: }
537: else if (xferred = ior->io_residual) {
538: ior->io_data -= xferred;
539: ior->io_count += xferred;
540: ior->io_recnum -= xferred / tgt->block_size;
541: ior->io_residual = 0;
542: } /* that's it */
543:
544: #ifdef CHECKSUM
545: if ((ior->io_op & IO_READ) && (ior->io_count < max_checksum_size)) {
546: part = rzpartition(ior->io_unit);
547: label=lookup_part(tgt->dev_info.disk.scsi_array, part);
548: if (!label) printf("NOT FOUND!\n");
549: secno = ior->io_recnum + label->start;
550: scdisk_bcheck(secno, ior->io_data, ior->io_count);
551: }
552: #endif CHECKSUM
553:
554: /* dequeue next one */
555: {
556: io_req_t next;
557:
558: simple_lock(&tgt->target_lock);
559: next = ior->io_next;
560: tgt->ior = next;
561: simple_unlock(&tgt->target_lock);
562:
563: iodone(ior);
564: if (next == 0)
565: return;
566:
567: ior = next;
568: }
569:
570: #ifdef CHECKSUM
571: if (((ior->io_op & IO_READ) == 0) && (ior->io_count < max_checksum_size)) {
572: part = rzpartition(ior->io_unit);
573: label=lookup_part(tgt->dev_info.disk.scsi_array, part);
574: secno = ior->io_recnum + label->start;
575: scdisk_checksum(secno, ior->io_data, ior->io_count);
576: }
577: #endif CHECKSUM
578: }
579: ior->io_residual = 0;
580: start:
581: scdisk_start_rw( tgt, ior);
582: }
583:
584: void scdisk_start_rw( tgt, ior)
585: target_info_t *tgt;
586: register io_req_t ior;
587: {
588: unsigned int part, secno;
589: register boolean_t long_form;
590: struct diskpart *label;
591:
592: part = rzpartition(ior->io_unit);
593: label=lookup_part(tgt->dev_info.disk.scsi_array, part);
594: if (!label)
595: printf("NOT FOUND!\n");
596: secno = ior->io_recnum + label->start;
597:
598: /* Use long form if either big block addresses or
599: the size is more than we can fit in one byte */
600: long_form = (tgt->flags & TGT_BIG) ||
601: (ior->io_count > (256 * tgt->block_size));
602: if (ior->io_op & IO_READ)
603: (long_form ? scsi_long_read : scdisk_read)(tgt, secno, ior);
604: else if ((ior->io_op & IO_INTERNAL) == 0)
605: (long_form ? scsi_long_write : scdisk_write)(tgt, secno, ior);
606: }
607:
608: #include <sys/ioctl.h>
609: #ifdef ULTRIX_COMPAT
610: #include <mips/PMAX/rzdisk.h>
611: #endif /*ULTRIX_COMPAT*/
612:
613: io_return_t
614: scdisk_get_status(dev, tgt, flavor, status, status_count)
615: int dev;
616: target_info_t *tgt;
617: dev_flavor_t flavor;
618: dev_status_t status;
619: natural_t *status_count;
620: {
621: struct disklabel *lp;
622: struct diskpart *label;
623:
624: lp = &tgt->dev_info.disk.l;
625:
626: switch (flavor) {
627: #ifdef MACH_KERNEL
628: case DEV_GET_SIZE:
629:
630: label=lookup_part(tgt->dev_info.disk.scsi_array, rzpartition(dev));
631: status[DEV_GET_SIZE_DEVICE_SIZE] = label->size * lp->d_secsize;
632: status[DEV_GET_SIZE_RECORD_SIZE] = tgt->block_size;
633: *status_count = DEV_GET_SIZE_COUNT;
634: break;
635: #endif
636:
637: case DIOCGDINFO:
638: *(struct disklabel *)status = *lp;
639: #ifdef MACH_KERNEL
640: *status_count = sizeof(struct disklabel)/sizeof(int);
641: #endif MACH_KERNEL
642: break;
643:
644: case DIOCGDINFO - (0x10<<16):
645: *(struct disklabel *)status = *lp;
646: #ifdef MACH_KERNEL
647: *status_count = sizeof(struct disklabel)/sizeof(int) - 4;
648: #endif MACH_KERNEL
649: break;
650:
651: #ifdef MACH_KERNEL
652: #else /*MACH_KERNEL*/
653: #if ULTRIX_COMPAT
654: case SCSI_MODE_SENSE: /*_IOWR(p, 9, struct mode_sel_sns_params) */
655: break;
656: case DIOCGETPT: /*_IOR(p, 1, struct pt) */
657: case SCSI_GET_SENSE: /*_IOR(p, 10, struct extended_sense) */
658: return ul_disk_ioctl(tgt, flavor, status, status_count);
659: #endif /*ULTRIX_COMPAT*/
660: #endif /*!MACH_KERNEL*/
661:
662: #if 0
663: case DIOCRFORMAT:
664: break;
665: #endif
666: default:
667: #ifdef i386
668: return(scsi_i386_get_status(dev, tgt, flavor, status, status_count));
669: #else i386
670: return(D_INVALID_OPERATION);
671: #endif i386
672: }
673: return D_SUCCESS;
674: }
675:
676: io_return_t
677: scdisk_set_status(dev, tgt, flavor, status, status_count)
678: int dev;
679: target_info_t *tgt;
680: dev_flavor_t flavor;
681: dev_status_t status;
682: natural_t status_count;
683: {
684: io_return_t error = D_SUCCESS;
685: struct disklabel *lp;
686:
687: lp = &tgt->dev_info.disk.l;
688:
689:
690: switch (flavor) {
691: case DIOCSRETRIES:
692: #ifdef MACH_KERNEL
693: if (status_count != sizeof(int))
694: return D_INVALID_SIZE;
695: #endif /* MACH_KERNEL */
696: scsi_bbr_retries = *(int *)status;
697: break;
698:
699: case DIOCWLABEL:
700: case DIOCWLABEL - (0x10<<16):
701: if (*(int*)status)
702: tgt->flags |= TGT_WRITE_LABEL;
703: else
704: tgt->flags &= ~TGT_WRITE_LABEL;
705: break;
706: case DIOCSDINFO:
707: case DIOCSDINFO - (0x10<<16):
708: case DIOCWDINFO:
709: case DIOCWDINFO - (0x10<<16):
710: #ifdef MACH_KERNEL
711: if (status_count != sizeof(struct disklabel) / sizeof(int))
712: return D_INVALID_SIZE;
713: #endif /* MACH_KERNEL */
714: error = setdisklabel(lp, (struct disklabel*) status);
715: if (error || (flavor == DIOCSDINFO) || (flavor == DIOCSDINFO - (0x10<<16)))
716: return error;
717: error = scdisk_writelabel(tgt);
718: break;
719:
720: #ifdef MACH_KERNEL
721: #else /*MACH_KERNEL*/
722: #if ULTRIX_COMPAT
723: case SCSI_FORMAT_UNIT: /*_IOW(p, 4, struct format_params) */
724: case SCSI_REASSIGN_BLOCK: /*_IOW(p, 5, struct reassign_params) */
725: case SCSI_READ_DEFECT_DATA: /*_IOW(p, 6, struct read_defect_params) */
726: case SCSI_VERIFY_DATA: /*_IOW(p, 7, struct verify_params) */
727: case SCSI_MODE_SELECT: /*_IOW(p, 8, struct mode_sel_sns_params) */
728: case SCSI_MODE_SENSE: /*_IOW(p, 9, struct mode_sel_sns_params) */
729: case SCSI_GET_INQUIRY_DATA: /*_IOW(p, 11, struct inquiry_info) */
730: return ul_disk_ioctl(tgt, flavor, status, status_count);
731: #endif /*ULTRIX_COMPAT*/
732: #endif /*!MACH_KERNEL*/
733:
734: #if notyet
735: case DIOCWFORMAT:
736: case DIOCSBAD: /* ?? how ? */
737: #endif
738: default:
739: #ifdef i386
740: error = scsi_i386_set_status(dev, tgt, flavor, status, status_count);
741: #else i386
742: error = D_INVALID_OPERATION;
743: #endif i386
744: }
745: return error;
746: }
747:
748: static int grab_it(tgt, ior)
749: target_info_t *tgt;
750: io_req_t ior;
751: {
752: spl_t s;
753:
754: s = splbio();
755: simple_lock(&tgt->target_lock);
756: if (!tgt->ior)
757: tgt->ior = ior;
758: simple_unlock(&tgt->target_lock);
759: splx(s);
760:
761: if (tgt->ior != ior)
762: return D_ALREADY_OPEN;
763: return D_SUCCESS;
764: }
765:
766: /* Write back a label to the disk */
767: io_return_t scdisk_writelabel(tgt)
768: target_info_t *tgt;
769: {
770:
771: printf("scdisk_writelabel: NO LONGER IMPLEMENTED\n");
772: #if 0
773: /* Taken out at Bryan's suggestion until 'fixed' for slices */
774:
775: io_req_t ior;
776: char *data = (char *)0;
777: struct disklabel *label;
778: io_return_t error;
779: int dev_bsize = tgt->block_size;
780:
781: io_req_alloc(ior,0);
782: #ifdef MACH_KERNEL
783: data = (char *)kalloc(dev_bsize);
784: #else /*MACH_KERNEL*/
785: data = (char *)ior->io_data;
786: #endif /*MACH_KERNEL*/
787: ior->io_next = 0;
788: ior->io_prev = 0;
789: ior->io_data = data;
790: ior->io_count = dev_bsize;
791: ior->io_op = IO_READ;
792: ior->io_error = 0;
793:
794: if (grab_it(tgt, ior) != D_SUCCESS) {
795: error = D_ALREADY_OPEN;
796: goto ret;
797: }
798:
799: scdisk_read( tgt, tgt->dev_info.disk.labelsector, ior);
800: iowait(ior);
801: if (error = ior->io_error)
802: goto ret;
803:
804: label = (struct disklabel *) &data[tgt->dev_info.disk.labeloffset];
805: *label = tgt->dev_info.disk.l;
806:
807: ior->io_next = 0;
808: ior->io_prev = 0;
809: ior->io_data = data;
810: ior->io_count = dev_bsize;
811: ior->io_op = IO_WRITE;
812:
813: while (grab_it(tgt, ior) != D_SUCCESS) ; /* ahem */
814:
815: scdisk_write( tgt, tgt->dev_info.disk.labelsector, ior);
816: iowait(ior);
817:
818: error = ior->io_error;
819: ret:
820: #ifdef MACH_KERNEL
821: if (data) kfree((int)data, dev_bsize);
822: #endif /*MACH_KERNEL*/
823: io_req_free(ior);
824: return error;
825:
826: #endif 0 scdisk_writelabel
827: return -1; /* FAILURE ? */
828: }
829:
830: #ifdef MACH_KERNEL
831: #else /*MACH_KERNEL*/
832: #if ULTRIX_COMPAT
833:
834: io_return_t ul_disk_ioctl(tgt, flavor, status, status_count)
835: target_info_t *tgt;
836: dev_flavor_t flavor;
837: dev_status_t status;
838: natural_t status_count;
839: {
840: io_return_t ret;
841: scsi_ret_t err = SCSI_RET_ABORTED;/*xxx*/
842: io_req_t ior;
843:
844: if (!suser())
845: return EACCES;
846:
847: ior = geteblk(sizeof(struct defect_descriptors));
848: ior->io_next = 0;
849: ior->io_count = 0;
850: ior->io_op = IO_INTERNAL;
851: ior->io_error = 0;
852: ior->io_recnum = 0;
853: ior->io_residual = 0;
854:
855: switch (flavor) {
856:
857: case DIOCGETPT: { /*_IOR(p, 1, struct pt) */
858: scsi_dec_label_t *p;
859: struct disklabel *lp;
860: int i;
861:
862: lp = &tgt->dev_info.disk.l;
863: p = (scsi_dec_label_t *)status;
864:
865: p->magic = DEC_PARTITION_MAGIC;
866: p->in_use = 1;
867: for (i = 0; i < 8; i++) {
868: label=lookup_part(tgt->dev_info.disk.scsi_array, part);
869: p->partitions[i].n_sectors = label->size;
870: p->partitions[i].offset = label->start;
871: }
872: err = SCSI_RET_SUCCESS;
873: }
874: break;
875:
876: case SCSI_GET_SENSE: { /*_IOR(p, 10, struct extended_sense) */
877: scsi_sense_data_t *s;
878:
879: s = (scsi_sense_data_t*)tgt->cmd_ptr;
880: bcopy(s, status, sizeof(*s) + s->u.xtended.add_len - 1);
881: err = SCSI_RET_SUCCESS;
882: /* only once */
883: bzero(tgt->cmd_ptr, sizeof(scsi_sense_data_t));
884: }
885: break;
886:
887: case SCSI_GET_INQUIRY_DATA: { /*_IOR(p, 11, struct inquiry_info) */
888: struct mode_sel_sns_params *ms;
889:
890: ms = (struct mode_sel_sns_params*)status;
891: err = scsi_inquiry( tgt, SCSI_INQ_STD_DATA);
892: if (copyout(tgt->cmd_ptr, ms->msp_addr, sizeof(struct inquiry_info))){
893: ret = EFAULT;
894: goto out;
895: }
896: }
897: break;
898:
899: case SCSI_FORMAT_UNIT: { /*_IOW(p, 4, struct format_params) */
900: struct format_params *fp;
901: struct defect_descriptors *df;
902: unsigned char mode;
903: unsigned int old_timeout;
904:
905: fp = (struct format_params *)status;
906: df = (struct defect_descriptors*)ior->io_data;
907: if (fp->fp_length != 0) {
908: if (copyin(fp->fp_addr, df, sizeof(*df))) {
909: ret = EFAULT;
910: goto out;
911: }
912: ior->io_count = sizeof(*df);
913: } else
914: ior->io_count = 0;
915: mode = fp->fp_format & SCSI_CMD_FMT_LIST_TYPE;
916: switch (fp->fp_defects) {
917: case VENDOR_DEFECTS:
918: mode |= SCSI_CMD_FMT_FMTDATA|SCSI_CMD_FMT_CMPLIST;
919: break;
920: case KNOWN_DEFECTS:
921: mode |= SCSI_CMD_FMT_FMTDATA;
922: break;
923: case NO_DEFECTS:
924: default:
925: break;
926: }
927: old_timeout = scsi_watchdog_period;
928: scsi_watchdog_period = 60*60; /* 1 hour should be enough, I hope */
929: err = scsi_format_unit( tgt, mode, fp->fp_pattern,
930: fp->fp_interleave, ior);
931: scsi_watchdog_period = old_timeout;
932: /* Make sure we re-read all info afresh */
933: tgt->flags = TGT_ALIVE |
934: (tgt->flags & (TGT_REMOVABLE_MEDIA|TGT_FULLY_PROBED));
935: }
936: break;
937:
938: case SCSI_REASSIGN_BLOCK: { /*_IOW(p, 5, struct reassign_params) */
939: struct reassign_params *r;
940: int ndef;
941:
942: r = (struct reassign_params*) status;
943: ndef = r->rp_header.defect_len0 | (r->rp_header.defect_len1 >> 8);
944: ndef >>= 2;
945: tgt->ior = ior;
946: (void) scsi_reassign_blocks( tgt, &r->rp_lbn3, ndef, ior);
947: iowait(ior);
948: err = tgt->done;
949: }
950: break;
951:
952: case SCSI_READ_DEFECT_DATA: { /*_IOW(p, 6, struct read_defect_params) */
953: struct read_defect_params *dp;
954:
955: dp = (struct read_defect_params *)status;
956: ior->io_count = ior->io_alloc_size;
957: if (dp->rdp_alclen > ior->io_count)
958: dp->rdp_alclen = ior->io_count;
959: else
960: ior->io_count = dp->rdp_alclen;
961: ior->io_op |= IO_READ;
962: tgt->ior = ior;
963: err = scsi_read_defect(tgt, dp->rdp_format|0x18, ior);
964: if (copyout(ior->io_data, dp->rdp_addr, dp->rdp_alclen)) {
965: ret = EFAULT;
966: goto out;
967: }
968: }
969: break;
970:
971: case SCSI_VERIFY_DATA: { /*_IOW(p, 7, struct verify_params) */
972: struct verify_params *v;
973: unsigned int old_timeout;
974:
975: old_timeout = scsi_watchdog_period;
976: scsi_watchdog_period = 5*60; /* 5 mins enough, I hope */
977: v = (struct verify_params *)status;
978: ior->io_count = 0;
979: err = scdisk_verify( tgt, v->vp_lbn, v->vp_length, ior);
980: scsi_watchdog_period = old_timeout;
981: }
982: break;
983:
984: case SCSI_MODE_SELECT: { /*_IOW(p, 8, struct mode_sel_sns_params) */
985: struct mode_sel_sns_params *ms;
986:
987: ms = (struct mode_sel_sns_params*)status;
988: if(copyin(ms->msp_addr, ior->io_data, ms->msp_length)) {
989: ret = EFAULT;
990: goto out;
991: }
992: err = scdisk_mode_select( tgt, DEV_BSIZE, ior, ior->io_data,
993: ms->msp_length, ms->msp_setps);
994: }
995: break;
996:
997: case SCSI_MODE_SENSE: { /*_IOWR(p, 9, struct mode_sel_sns_params) */
998: struct mode_sel_sns_params *ms;
999: unsigned char pagecode;
1000:
1001: ms = (struct mode_sel_sns_params*)status;
1002: pagecode = (ms->msp_pgcode & 0x3f) | (ms->msp_pgctrl << 6);
1003: err = scsi_mode_sense( tgt, pagecode, ms->msp_length, ior);
1004: if (copyout(tgt->cmd_ptr, ms->msp_addr, ms->msp_length)){
1005: ret = EFAULT;
1006: goto out;
1007: }
1008: }
1009: break;
1010: }
1011:
1012: ret = (err == SCSI_RET_SUCCESS) ? D_SUCCESS : D_IO_ERROR;
1013: if (ior->io_op & IO_ERROR)
1014: ret = D_IO_ERROR;
1015: out:
1016: brelse(ior);
1017: return ret;
1018: }
1019: #endif /*ULTRIX_COMPAT*/
1020: #endif /*!MACH_KERNEL*/
1021:
1022: #ifdef CHECKSUM
1023:
1024: #define SUMSIZE 0x10000
1025: #define SUMHASH(b) (((b)>>1) & (SUMSIZE - 1))
1026: struct {
1027: long blockno;
1028: long sum;
1029: } scdisk_checksums[SUMSIZE];
1030:
1031: void scdisk_checksum(bno, addr, size)
1032: long bno;
1033: register unsigned int *addr;
1034: {
1035: register int i = size/sizeof(int);
1036: register unsigned int sum = -1;
1037:
1038: while (i-- > 0)
1039: sum ^= *addr++;
1040: scdisk_checksums[SUMHASH(bno)].blockno = bno;
1041: scdisk_checksums[SUMHASH(bno)].sum = sum;
1042: }
1043:
1044: void scdisk_bcheck(bno, addr, size)
1045: long bno;
1046: register unsigned int *addr;
1047: {
1048: register int i = size/sizeof(int);
1049: register unsigned int sum = -1;
1050: unsigned int *start = addr;
1051:
1052: if (scdisk_checksums[SUMHASH(bno)].blockno != bno) {
1053: if (scsi_debug) printf("No checksum for block x%x\n", bno);
1054: return;
1055: }
1056:
1057: while (i-- > 0)
1058: sum ^= *addr++;
1059:
1060: if (scdisk_checksums[SUMHASH(bno)].sum != sum) {
1061: printf("Bad checksum (x%x != x%x), bno x%x size x%x at x%x\n",
1062: sum,
1063: scdisk_checksums[bno & (SUMSIZE - 1)].sum,
1064: bno, size, start);
1065: gimmeabreak();
1066: scdisk_checksums[SUMHASH(bno)].sum = sum;
1067: }
1068: }
1069:
1070:
1071: #endif CHECKSUM
1072:
1073: /*#define PERF */
1074: #ifdef PERF
1075: int test_read_size = 512;
1076: int test_read_skew = 12;
1077: int test_read_skew_min = 0;
1078: int test_read_nreads = 1000;
1079: int test_read_bdev = 0;
1080:
1081: #include <sys/time.h>
1082:
1083: void test_read(max)
1084: {
1085: int i, ssk, usecs;
1086: struct timeval start, stop;
1087:
1088: if (max == 0)
1089: max = test_read_skew + 1;
1090: ssk = test_read_skew;
1091: for (i = test_read_skew_min; i < max; i++){
1092: test_read_skew = i;
1093:
1094: start = time;
1095: read_test();
1096: stop = time;
1097:
1098: usecs = stop.tv_usec - start.tv_usec;
1099: if (usecs < 0) {
1100: stop.tv_sec -= 1;
1101: usecs += 1000000;
1102: }
1103: printf("Skew %3d size %d count %d time %3d sec %d us\n",
1104: i, test_read_size, test_read_nreads,
1105: stop.tv_sec - start.tv_sec, usecs);
1106: }
1107: test_read_skew = ssk;
1108: }
1109:
1110: void read_test()
1111: {
1112: static int buffer[(8192*2)/sizeof(int)];
1113: struct io_req io;
1114: register int i, rec;
1115:
1116: bzero(&io, sizeof(io));
1117: io.io_unit = test_read_bdev;
1118: io.io_op = IO_READ;
1119: io.io_count = test_read_size;
1120: io.io_data = (char*) buffer;
1121:
1122: for (rec = 0, i = 0; i < test_read_nreads; i++) {
1123: io.io_op = IO_READ;
1124: io.io_recnum = rec;
1125: scdisk_strategy(&io);
1126: rec += test_read_skew;
1127: iowait(&io);
1128: }
1129: }
1130:
1131: void tur_test()
1132: {
1133: struct io_req io;
1134: register int i;
1135: char *a, *b;
1136: struct timeval start, stop;
1137:
1138: bzero(&io, sizeof(io));
1139: io.io_unit = test_read_bdev;
1140: io.io_data = (char*)&io;/*unused but kernel space*/
1141:
1142: start = time;
1143: for (i = 0; i < test_read_nreads; i++) {
1144: io.io_op = IO_INTERNAL;
1145: rz_check(io.io_unit, &a, &b);
1146: scsi_test_unit_ready(b,&io);
1147: }
1148: stop = time;
1149: i = stop.tv_usec - start.tv_usec;
1150: if (i < 0) {
1151: stop.tv_sec -= 1;
1152: i += 1000000;
1153: }
1154: printf("%d test-unit-ready took %3d sec %d us\n",
1155: test_read_nreads,
1156: stop.tv_sec - start.tv_sec, i);
1157: }
1158:
1159: #endif PERF
1160:
1161: /*#define WDEBUG*/
1162: #ifdef WDEBUG
1163:
1164: int buggo_write_size = 8192;
1165: int buggo_dev = 2; /* rz0b */ /* changed by KTVM from 1 (still b) */
1166: int buggo_out_buffer[8192/2];
1167: int buggo_in_buffer[8192/2];
1168: int buggotest(n, pattern, verbose)
1169: {
1170: struct io_req io;
1171: register int i, rec;
1172:
1173: if (n <= 0)
1174: n = 1;
1175:
1176: if(pattern)
1177: for (i = 0; i < buggo_write_size/4; i++)
1178: buggo_out_buffer[i] = i + pattern;
1179:
1180: for (i = 0; i < n; i++) {
1181: register int j;
1182:
1183: buggo_out_buffer[0] = i + pattern;
1184: buggo_out_buffer[(buggo_write_size/4)-1] = i + pattern;
1185: bzero(&io, sizeof(io));
1186: io.io_unit = buggo_dev;
1187: io.io_data = (char*)buggo_out_buffer;
1188: io.io_op = IO_WRITE;
1189: io.io_count = buggo_write_size;
1190: io.io_recnum = i % 1024;
1191: scdisk_strategy(&io);
1192:
1193: bzero(buggo_in_buffer, sizeof(buggo_in_buffer));
1194: iowait(&io);
1195:
1196: if (verbose)
1197: printf("Done write with %x", io.io_error);
1198:
1199: bzero(&io, sizeof(io));
1200: io.io_unit = buggo_dev;
1201: io.io_data = (char*)buggo_in_buffer;
1202: io.io_op = IO_READ;
1203: io.io_count = buggo_write_size;
1204: io.io_recnum = i % 1024;
1205: scdisk_strategy(&io);
1206: iowait(&io);
1207:
1208: if (verbose)
1209: printf("Done read with %x", io.io_error);
1210:
1211: for (j = 0; j < buggo_write_size/4; j++)
1212: if (buggo_out_buffer[j] != buggo_in_buffer[j]){
1213: printf("Difference at %d-th word: %x %x\n",
1214: buggo_out_buffer[j], buggo_in_buffer[j]);
1215: return i;
1216: }
1217: }
1218: printf("Test ok\n");
1219: return n;
1220: }
1221: #endif WDEBUG
1222: #endif /* NSCSI > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.