|
|
1.1 root 1: /* @(#)sf.c 1.1 86/02/03 SMI */
2:
3: /*
4: * Copyright (c) 1984 by Sun Microsystems, Inc.
5: */
6:
7: #include "sf.h"
8: #if NSF > 0
9:
10: /*
11: * SCSI driver for SCSI floppy disks.
12: */
13: #include "../h/param.h"
14: #include "../h/systm.h"
15: #include "../h/dk.h"
16: #include "../h/buf.h"
17: #include "../h/conf.h"
18: #include "../h/user.h"
19: #include "../h/map.h"
20: #include "../h/vmmac.h"
21: /*
22: *#include "../h/ioctl.h"
23: *#include "../h/uio.h"
24: *#include "../h/kernel.h"
25: */
26: #include "../h/dkbad.h"
27: /*
28: *#include "../h/vfs.h"
29: *#include "../h/vnode.h"
30: */
31: #include "../machine/pte.h"
32: #include "../machine/psl.h"
33: #include "../machine/mmu.h"
34: #include "../machine/cpu.h"
35: #include "../sun/dklabel.h"
36: #include "../sun/dkio.h"
37: /*#include "../pcfs/pc_label.h"*/
38: #include "../sundev/mbvar.h"
39: #include "../sundev/screg.h"
40: #include "../sundev/sireg.h"
41: #include "../sundev/scsi.h"
42:
43: #define MAX_RETRIES 0
44: #define MAX_RESTORES 1
45:
46: #define SFUNIT(dev) (minor(dev))
47: #define SFNUM(un) (un - sfunits)
48:
49: #define b_cylin b_resid
50:
51: #define BUSY_RETRY 1000
52:
53: /*
54: * Error message control.
55: */
56: #define EL_RETRY 3
57: #define EL_REST 2
58: #define EL_FAIL 1
59: int sferrlvl = EL_REST;
60:
61: /*
62: * sf specific SCSI commands
63: */
64: #define SC_INIT_CHARACTERISTICS 0x0c /* initialize drive characteristics */
65:
66: extern struct scsi_unit sfunits[];
67: extern struct scsi_unit_subr scsi_unit_subr[];
68: extern struct scsi_floppy sfloppy[];
69: extern int nsfloppy;
70:
71: #define SF_LABELGET 0x01 /* getting device label */
72: #define SF_LABELWANT 0x02 /* waiting to get label */
73:
74: struct sf_characteristics {
75: u_char sfc_ncyl; /* number of cylinders */
76: u_int sfc_trkswtch : 4; /* track switching rate code */
77: u_int sfc_mstart : 12; /* motor start time (msec) */
78: u_char sfc_drive : 4; /* drive type (5 or 8 inch) */
79: u_char sfc_nhead : 4; /* number of heads */
80: u_char sfc_secsize; /* sector size / 256 */
81: u_char sfc_uload; /* head unload time in 1/10 sec */
82: u_char sfc_spt; /* sectors per track */
83: u_char sfc_record; /* recording density code */
84: };
85:
86: /*
87: * track switching codes
88: */
89: #define TS_6MSEC 0 /* 6 msec */
90: #define TS_12MSEC 1 /* 12 msec */
91: #define TS_20MSEC 2 /* 20 msec */
92: #define TS_30MSEC 3 /* 30 msec */
93:
94: /*
95: * recording density codes
96: */
97: #define SDENSITY 0x00 /* single denisity */
98: #define DDENSITY 0xC0 /* double density */
99:
100: static struct sf_characteristics default_characteristics = {
101: 40,
102: TS_6MSEC,
103: 500,
104: 5,
105: 2,
106: PC_SECSIZE/256,
107: 10,
108: 9,
109: DDENSITY
110: };
111:
112: static struct sf_characteristics current_characteristics;
113:
114: /*
115: * Return a pointer to this unit's unit structure.
116: */
117: sfunitptr(md)
118: register struct mb_device *md;
119: {
120: return ((int)&sfunits[md->md_unit]);
121: }
122:
123: /*
124: * Attach device (boot time).
125: */
126: sfattach(md)
127: register struct mb_device *md;
128: {
129: register struct scsi_unit *un;
130:
131: un = &sfunits[md->md_unit];
132: un->un_md = md;
133: un->un_mc = md->md_mc;
134: un->un_unit = md->md_unit;
135: un->un_target = TARGET(md->md_slave);
136: un->un_lun = LUN(md->md_slave);
137: un->un_ss = &scsi_unit_subr[TYPE(md->md_flags)];
138: }
139:
140: static int
141: getlabel(dev)
142: register dev_t dev;
143: {
144: register struct scsi_unit *un;
145: register char *bufp;
146: register struct scsi_floppy *dsi;
147: char c;
148:
149: un = &sfunits[SFUNIT(dev)];
150: dsi = &sfloppy[SFUNIT(dev)];
151: /*
152: * We don't want multiple opens going on at the same time.
153: */
154: while (dsi->sf_flags & SF_LABELGET) {
155: dsi->sf_flags |= SF_LABELWANT;
156: sleep((caddr_t)dsi, PRIBIO);
157: if (un->un_present)
158: return (1);
159: }
160: dsi->sf_flags |= SF_LABELGET;
161: dsi->sf_nblk = 8;
162: dsi->sf_spt = 8;
163: dsi->sf_nhead = 1;
164: if (sfcmd(dev, SC_TEST_UNIT_READY, 0, 0, (caddr_t)0)) {
165: uprintf("sf%d: not online\n", SFNUM(un));
166: goto out;
167: }
168: if (sfcmd(dev, SC_INIT_CHARACTERISTICS, 0,
169: sizeof(default_characteristics),
170: (caddr_t)&default_characteristics) ) {
171: uprintf("sf%d: cannot init drive\n", SFNUM(un));
172: goto out;
173: }
174: bufp = kmem_alloc(PC_SECSIZE);
175: if (sfcmd(dev, SC_READ, PC_FATBLOCK, PC_SECSIZE, bufp)) {
176: uprintf("sf%d: error reading label\n", SFNUM(un));
177: kmem_free(bufp, PC_SECSIZE);
178: goto out;
179: }
180: dsi->sf_mdb = bufp[0];
181: c = bufp[1] & bufp[2];
182: kmem_free(bufp, PC_SECSIZE);
183: if (c != 0xFF) {
184: uprintf("sf%d: bad label\n", SFNUM(un));
185: goto out;
186: }
187: switch (dsi->sf_mdb) {
188: case SS8SPT:
189: dsi->sf_spt = 8;
190: dsi->sf_nhead = 1;
191: dsi->sf_nblk = 320;
192: break;
193:
194: case DS8SPT:
195: dsi->sf_spt = 8;
196: dsi->sf_nhead = 2;
197: dsi->sf_nblk = 640;
198: break;
199:
200: case SS9SPT:
201: dsi->sf_spt = 9;
202: dsi->sf_nhead = 1;
203: dsi->sf_nblk = 360;
204: break;
205:
206: case DS9SPT:
207: dsi->sf_spt = 9;
208: dsi->sf_nhead = 2;
209: dsi->sf_nblk = 720;
210: break;
211:
212: default:
213: uprintf("sf%d: bad label\n", SFNUM(un));
214: goto out;
215: }
216: current_characteristics = default_characteristics;
217: current_characteristics.sfc_spt = dsi->sf_spt;
218: current_characteristics.sfc_nhead = dsi->sf_nhead;
219: if (sfcmd(dev, SC_INIT_CHARACTERISTICS, 0,
220: sizeof(current_characteristics),
221: (caddr_t)¤t_characteristics)) {
222: uprintf("sf%d: cannot reinit drive\n", SFNUM(un));
223: } else {
224: un->un_present = 1;
225: }
226: out:
227: dsi->sf_flags &= ~SF_LABELGET;
228: if (dsi->sf_flags & SF_LABELWANT) {
229: dsi->sf_flags &= ~SF_LABELWANT;
230: wakeup((caddr_t)dsi);
231: }
232: return (un->un_present);
233: }
234:
235: /*ARGSUSED*/
236: sfopen(dev, flag)
237: dev_t dev;
238: int flag;
239: {
240: register struct scsi_unit *un;
241: register int unit;
242:
243: unit = SFUNIT(dev);
244: if (unit >= nsfloppy) {
245: return (ENXIO);
246: }
247: un = &sfunits[unit];
248: if (un->un_mc == 0) { /* never attached */
249: return (ENXIO);
250: }
251: if (!un->un_present) {
252: if (!getlabel(dev)) {
253: return (EIO);
254: }
255: }
256: return (0);
257: }
258:
259: /*ARGSUSED*/
260: sfclose(dev, flag)
261: dev_t dev;
262: int flag;
263: {
264: register struct scsi_unit *un;
265:
266: un = &sfunits[SFUNIT(dev)];
267: /*
268: * make the driver get the label again on the next open
269: */
270: un->un_present = 0;
271: }
272:
273: sfsize(dev)
274: register dev_t dev;
275: {
276: register struct scsi_unit *un;
277:
278: un = &sfunits[SFUNIT(dev)];
279: if (!un->un_present) {
280: return (-1);
281: }
282: return (sfloppy[SFUNIT(dev)].sf_nblk);
283: }
284:
285: sfstrategy(bp)
286: register struct buf *bp;
287: {
288: register struct scsi_unit *un;
289: register daddr_t bn;
290: register int unit, s;
291: register struct buf *dp;
292: register struct scsi_floppy *dsi;
293:
294: unit = SFUNIT(bp->b_dev);
295: if (unit >= nsfloppy) {
296: printf("sf%d: sfstrategy: invalid unit\n", unit);
297: bp->b_flags |= B_ERROR;
298: iodone(bp);
299: return;
300: }
301: un = &sfunits[unit];
302: dsi = &sfloppy[unit];
303: bn = dkblock(bp);
304: if ((!un->un_present && bp != &un->un_sbuf) || (bn > dsi->sf_nblk)) {
305: bp->b_flags |= B_ERROR;
306: iodone(bp);
307: return;
308: }
309: if (un->un_present) {
310: if (bn == dsi->sf_nblk) { /* EOF */
311: bp->b_resid = bp->b_bcount;
312: iodone(bp);
313: return;
314: }
315: bp->b_cylin = bn / (dsi->sf_spt * dsi->sf_nhead);
316: } else {
317: bp->b_cylin = 0;
318: }
319: dp = &un->un_utab;
320: s = splx(pritospl(un->un_mc->mc_intpri));
321: disksort(dp, bp);
322: if (dp->b_active == 0) {
323: (*un->un_c->c_ss->scs_ustart)(un);
324: bp = &un->un_mc->mc_tab;
325: if (bp->b_actf && bp->b_active == 0) {
326: (*un->un_c->c_ss->scs_start)(un);
327: }
328: }
329: (void) splx(s);
330: }
331:
332: /*
333: * Do a special command.
334: */
335: sfcmd(dev, cmd, sector, len, addr)
336: register dev_t dev;
337: register int cmd, sector, len;
338: register caddr_t addr;
339: {
340: register struct scsi_unit *un;
341: register struct buf *bp;
342: register int s;
343:
344: un = &sfunits[SFUNIT(dev)];
345: bp = &un->un_sbuf;
346: s = splx(pritospl(un->un_mc->mc_intpri));
347: while (bp->b_flags&B_BUSY) {
348: bp->b_flags |= B_WANTED;
349: sleep((caddr_t)bp, PRIBIO);
350: }
351: bp->b_flags = B_BUSY|B_READ;
352: (void) splx(s);
353: un->un_scmd = cmd;
354: bp->b_dev = dev;
355: bp->b_blkno = sector;
356: bp->b_un.b_addr = addr;
357: bp->b_bcount = len;
358: sfstrategy(bp);
359: iowait(bp);
360: bp->b_flags &= ~B_BUSY;
361: if (bp->b_flags&B_WANTED)
362: wakeup((caddr_t)bp);
363: return (bp->b_flags & B_ERROR);
364: }
365:
366: /*
367: * Set up a transfer for the controller
368: */
369: sfstart(bp, un)
370: register struct buf *bp;
371: register struct scsi_unit *un;
372: {
373: register int nblk;
374: register struct scsi_floppy *dsi;
375:
376: dsi = &sfloppy[SFUNIT(bp->b_dev)];
377: un->un_blkno = dkblock(bp);
378: if (bp == &un->un_sbuf) {
379: un->un_cmd = un->un_scmd;
380: } else if (bp->b_flags & B_READ) {
381: un->un_cmd = SC_READ;
382: } else {
383: un->un_cmd = SC_WRITE;
384: }
385: if (un->un_cmd == SC_READ || un->un_cmd == SC_WRITE) {
386: nblk = howmany(bp->b_bcount, PC_SECSIZE);
387: un->un_count = MIN(nblk, dsi->sf_nblk - bp->b_blkno);
388: bp->b_resid = bp->b_bcount - un->un_count * PC_SECSIZE;
389: un->un_flags |= SC_UNF_DVMA;
390: } else {
391: if (un->un_cmd == SC_INIT_CHARACTERISTICS)
392: un->un_flags |= SC_UNF_DVMA;
393: un->un_count = bp->b_bcount;
394: }
395: return (1);
396: }
397:
398: /*
399: * Make a cdb for disk i/o.
400: */
401: sfmkcdb(c, un)
402: register struct scsi_ctlr *c;
403: struct scsi_unit *un;
404: {
405: register struct scsi_cdb *cdb;
406:
407: cdb = &c->c_cdb;
408: bzero((caddr_t)cdb, sizeof (*cdb));
409: un->un_dma_addr = 0;
410: un->un_dma_count = 0;
411: cdb->cmd = un->un_cmd;
412: cdb->lun = un->un_lun;
413: switch (un->un_cmd) {
414: case SC_TEST_UNIT_READY:
415: case SC_REZERO_UNIT:
416: case SC_REQUEST_SENSE:
417: break;
418: case SC_SEEK:
419: cdbaddr(cdb, un->un_blkno);
420: break;
421: case SC_READ:
422: case SC_WRITE:
423: cdbaddr(cdb, un->un_blkno);
424: cdb->count = un->un_count;
425: un->un_dma_addr = un->un_baddr;
426: un->un_dma_count = un->un_count * PC_SECSIZE;
427: break;
428: case SC_INIT_CHARACTERISTICS:
429: un->un_dma_addr = un->un_baddr;
430: un->un_dma_count = un->un_count;
431: break;
432: default:
433: panic("sfmkcdb");
434: break;
435: }
436: }
437:
438: /*
439: * Interrupt processing.
440: */
441: sfintr(c, resid, error)
442: register struct scsi_ctlr *c;
443: register int resid, error;
444: {
445: register struct scsi_unit *un;
446: register struct buf *bp;
447: register struct mb_device *md;
448:
449: un = c->c_un;
450: bp = un->un_mc->mc_tab.b_actf->b_actf;
451: md = un->un_md;
452: if (md->md_dk >= 0) {
453: dk_busy &= ~(1 << md->md_dk);
454: }
455: if (error == SE_FATAL) {
456: if (bp == &un->un_sbuf &&
457: ((un->un_flags & SC_UNF_DVMA) == 0)) {
458: (*c->c_ss->scs_done)(un->un_mc);
459: } else {
460: mbdone(un->un_mc);
461: un->un_flags &= ~SC_UNF_DVMA;
462: }
463: bp->b_flags |= B_ERROR;
464: printf("sf%d: SCSI FAILURE\n", SFNUM(un));
465: (*c->c_ss->scs_off)(un);
466: return;
467: }
468: if (error == SE_RETRYABLE || c->c_scb.chk || resid > 0) {
469: sferror(c, un, bp);
470: return;
471: }
472: if (c->c_cdb.cmd == SC_REZERO_UNIT &&
473: !(bp == &un->un_sbuf &&
474: un->un_scmd == SC_REZERO_UNIT)) {
475: /* error recovery */
476: sfmkcdb(c, un);
477: if ((*c->c_ss->scs_cmd)(c, un, 1) == 0) {
478: printf("sf%d sfintr: scsi cmd failed 1\n", SFNUM(un));
479: (*c->c_ss->scs_off)(un);
480: }
481: return;
482: }
483: /* transfer worked */
484: un->un_retries = un->un_restores = 0;
485: if (un->un_sec_left) { /* single sector stuff */
486: un->un_sec_left--;
487: un->un_baddr += PC_SECSIZE;
488: un->un_blkno++;
489: sfmkcdb(c, un);
490: if ((*c->c_ss->scs_cmd)(c, un, 1) == 0) {
491: printf("sf%d: sfintr: scsi cmd failed 2\n", SFNUM(un));
492: (*c->c_ss->scs_off)(un);
493: }
494: } else if (bp == &un->un_sbuf &&
495: ((un->un_flags & SC_UNF_DVMA) == 0)) {
496: (*c->c_ss->scs_done)(un->un_mc);
497: } else {
498: mbdone(un->un_mc);
499: un->un_flags &= ~SC_UNF_DVMA;
500: }
501: }
502:
503: /*
504: * Error handling.
505: */
506: sferror(c, un, bp)
507: register struct scsi_ctlr *c;
508: register struct scsi_unit *un;
509: register struct buf *bp;
510: {
511:
512: if (un->un_present == 0) { /* error trying to open */
513: bp->b_flags |= B_ERROR;
514: if (bp == &un->un_sbuf &&
515: ((un->un_flags & SC_UNF_DVMA) == 0)) {
516: (*c->c_ss->scs_done)(un->un_mc);
517: } else {
518: mbdone(un->un_mc);
519: un->un_flags &= ~SC_UNF_DVMA;
520: }
521: } else if (un->un_retries++ < MAX_RETRIES) {
522: /* retry */
523: if (sferrlvl >= EL_RETRY) {
524: sferrmsg(c, un, bp, "retry");
525: }
526: if ((*c->c_ss->scs_cmd)(c, un, 1) == 0) {
527: printf("sf%d: sferror: scsi cmd failed 2\n", SFNUM(un));
528: (*c->c_ss->scs_off)(un);
529: }
530: } else if (un->un_restores++ < MAX_RESTORES) {
531: /* retries exhausted, try restore */
532: un->un_retries = 0;
533: if (sferrlvl >= EL_REST) {
534: sferrmsg(c, un, bp, "restore");
535: }
536: c->c_cdb.cmd = SC_REZERO_UNIT;
537: cdbaddr(&c->c_cdb, 0);
538: c->c_cdb.count = 0;
539: un->un_dma_addr = un->un_dma_count = 0;
540: if ((*c->c_ss->scs_cmd)(c, un, 1) == 0) {
541: printf("sf%d: sferror: scsi cmd failed 3\n", SFNUM(un));
542: (*c->c_ss->scs_off)(un);
543: }
544: } else {
545: /* complete failure */
546: if (sferrlvl >= EL_FAIL) {
547: sferrmsg(c, un, bp, "failed");
548: }
549: (*c->c_ss->scs_off)(un);
550: bp->b_flags |= B_ERROR;
551: if (bp == &un->un_sbuf &&
552: ((un->un_flags & SC_UNF_DVMA) == 0)) {
553: (*c->c_ss->scs_done)(un->un_mc);
554: } else {
555: mbdone(un->un_mc);
556: un->un_flags &= ~SC_UNF_DVMA;
557: }
558: }
559: }
560:
561: sfread(dev, uio)
562: dev_t dev;
563: struct uio *uio;
564: {
565:
566: return (sfrw(dev, uio, B_READ));
567: }
568:
569: sfrw(dev, uio, direction)
570: dev_t dev;
571: struct uio *uio;
572: int direction;
573: {
574: register struct scsi_unit *un;
575: register int unit;
576:
577: unit = SFUNIT(dev);
578: if (unit >= nsfloppy) {
579: return (ENXIO);
580: }
581: un = &sfunits[unit];
582: if ((uio->uio_offset % DEV_BSIZE) != 0) {
583: return (EINVAL);
584: }
585: if ((uio->uio_iov->iov_len % DEV_BSIZE) != 0) {
586: return (EINVAL);
587: }
588: return (physio(sfstrategy, &un->un_rbuf, dev, direction, minphys,uio));
589: }
590:
591: sfwrite(dev, uio)
592: dev_t dev;
593: struct uio *uio;
594: {
595:
596: return (sfrw(dev, uio, B_WRITE));
597: }
598:
599: /*ARGSUSED*/
600: sfioctl(dev, cmd, data, flag)
601: register dev_t dev;
602: register caddr_t data;
603: {
604: register struct scsi_unit *un;
605: register struct dk_info *inf;
606: register int unit;
607:
608: unit = SFUNIT(dev);
609: if (unit >= nsfloppy) {
610: return (ENXIO);
611: }
612: un = &sfunits[unit];
613: switch (cmd) {
614:
615: case DKIOCINFO:
616: inf = (struct dk_info *)data;
617: inf->dki_ctlr = getdevaddr(un->un_mc->mc_addr);
618: inf->dki_unit = un->un_md->md_slave;
619: inf->dki_ctype = DKC_SCSI;
620: inf->dki_flags = DKI_FMTVOL;
621: break;
622:
623: default:
624: return (ENOTTY);
625: }
626: return (0);
627: }
628:
629: static char *sf_class_00_errors[] = {
630: "invalid sense code",
631: "invalid sense code",
632: "no seek complete",
633: "invalid sense code",
634: "drive not ready",
635: "invalid sense code",
636: "no track 00",
637: "door open",
638: "media not loaded",
639: };
640:
641: static char *sf_class_01_errors[] = {
642: "I.D. CRC error",
643: "write fault",
644: "write protected",
645: "invalid sense code",
646: "sector not found",
647: "seek error",
648: "(0x16) unformatted or bad format on drive",
649: "(0x17) unformatted or bad format on drive",
650: "invalid sense code",
651: "two sided error",
652: "wrong data mark found",
653: "pad error",
654: "invalid sense code",
655: "lost data in FDC",
656: "CRC error",
657: "FDC failure",
658: };
659:
660: static char *sf_class_02_errors[] = {
661: "invalid command",
662: "illegal block address",
663: "invalid cdb",
664: "invalid interleave",
665: };
666:
667: static char *sf_class_03_errors[] = {
668: "RAM error",
669: "controller program memory checksum error",
670: };
671:
672: static char **sf_errors[] = {
673: sf_class_00_errors,
674: sf_class_01_errors,
675: sf_class_02_errors,
676: sf_class_03_errors,
677: };
678:
679: int sf_errct[] = {
680: sizeof sf_class_00_errors / sizeof (char *),
681: sizeof sf_class_01_errors / sizeof (char *),
682: sizeof sf_class_02_errors / sizeof (char *),
683: sizeof sf_class_03_errors / sizeof (char *),
684: };
685:
686: char *sf_cmds[] = {
687: "test unit ready",
688: "rezero unit",
689: "bad cmd",
690: "request sense",
691: "bad cmd",
692: "bad cmd",
693: "bad cmd",
694: "bad cmd",
695: "read",
696: "bad cmd",
697: "write",
698: "seek",
699: "initialize characteristics",
700: };
701:
702: /*ARGSUSED*/
703: sferrmsg(c, un, bp, action)
704: register struct scsi_ctlr *c;
705: struct scsi_unit *un;
706: struct buf *bp;
707: char *action;
708: {
709: char *sensemsg, *cmdname;
710: register struct scsi_sense *sense;
711: register int blkno;
712:
713: sense = c->c_sense;
714: if (c->c_scb.chk == 0) {
715: sensemsg = "invalid sense code";
716: } else if (sense->class <= 3) {
717: if (sense->code < sf_errct[sense->class]) {
718: sensemsg = sf_errors[sense->class][sense->code];
719: } else {
720: sensemsg = "invalid sense code";
721: }
722: } else {
723: sensemsg = "invalid sense class";
724: }
725: if (un->un_cmd < sizeof(sf_cmds)) {
726: cmdname = sf_cmds[un->un_cmd];
727: } else {
728: cmdname = "bad cmd";
729: }
730: blkno = (sense->high_addr << 16) | (sense->mid_addr << 8) |
731: sense->low_addr;
732: printf("sf%d: %s %s (%s) blk %d\n", SFNUM(un),
733: cmdname, action, sensemsg, blkno);
734: }
735: #endif NSF > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.