1 /*
2 * Copyright (c) 1992 OMRON Corporation.
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * OMRON Corporation.
8 *
9 * %sccs.include.redist.c%
10 *
11 * @(#)sd.c 8.3 (Berkeley) 12/07/93
12 */
13
14 /*
15 * sd.c -- SCSI Disk Device Driver
16 * remaked by A.Fujita, MAR-22-1992
17 */
18
19 /*
20 * SCSI CCS (Command Command Set) disk driver.
21 */
22 #include "sd.h"
23 #if NSD > 0
24
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/buf.h>
28 #include <sys/dkstat.h>
29 #include <sys/proc.h>
30 #include <sys/disklabel.h>
31
32 #include <luna68k/dev/device.h>
33 #include <luna68k/dev/screg.h>
34 #include <luna68k/dev/scvar.h>
35
36 int sdinit(), sdstrategy(), sdstart(), sdintr();
37
38 struct driver sddriver = {
39 sdinit, "sd", sdstart, (int (*)()) 0, sdintr, (int (*)()) 0
40 };
41
42 struct disklabel sdlabel[NSD];
43
44 struct sd_softc {
45 struct hp_device *sc_hd;
46 struct scsi_queue sc_dq;
47 short sc_flags;
48 short sc_type; /* drive type */
49 short sc_punit; /* physical unit (scsi lun) */
50 u_int sc_blks; /* number of blocks on device */
51 int sc_blksize; /* device block size in bytes */
52 u_int sc_wpms; /* average xfer rate in 16 bit wds/sec. */
53 } sd_softc[NSD];
54
55 /* sc_flags values */
56 #define SDF_ALIVE 0x1
57
58 struct buf sdtab[NSD];
59 struct scsi_fmt_sense sdsense[NSD];
60
61 static struct scsi_fmt_cdb sd_read_cmd = { 10, CMD_READ_EXT };
62 static struct scsi_fmt_cdb sd_write_cmd = { 10, CMD_WRITE_EXT };
63
64 #define sdunit(x) ((minor(x) >> 3) & 0x7)
65 #define sdpart(x) (minor(x) & 0x7)
66 #define sdpunit(x) ((x) & 7)
67 #define sdminor(unit, part) (((unit) << 3) | (part))
68
69 #define b_lba b_resid
70
71 #define SDRETRY 3 /* IO retry count */
72
73 struct sd_iostat {
74 int imax;
75 int imin;
76 int omax;
77 int omin;
78 };
79
80 struct sd_iostat sd_iostat[NSD] = {
81 { 14000, -1, 100, -1 },
82 };
83
84 /*
85 * Initialize
86 */
87
88 int
sdinit(hd)89 sdinit(hd)
90 register struct hp_device *hd;
91 {
92 register struct sd_softc *sc = &sd_softc[hd->hp_unit];
93 register struct disklabel *lp;
94 char *msg, *sdreadlabel();
95
96 sc->sc_hd = hd;
97 sc->sc_punit = sdpunit(hd->hp_flags);
98 sc->sc_type = sdident(sc, hd);
99 if (sc->sc_type < 0)
100 return(0);
101 sc->sc_dq.dq_ctlr = hd->hp_ctlr;
102 sc->sc_dq.dq_unit = hd->hp_unit;
103 sc->sc_dq.dq_slave = hd->hp_slave;
104 sc->sc_dq.dq_driver = &sddriver;
105
106 /*
107 * Use the default sizes until we've read the label,
108 * or longer if there isn't one there.
109 */
110 lp = &sdlabel[hd->hp_unit];
111
112 if (lp->d_secpercyl == 0) {
113 lp->d_secsize = DEV_BSIZE;
114 lp->d_nsectors = 32;
115 lp->d_ntracks = 20;
116 lp->d_secpercyl = 32*20;
117 lp->d_npartitions = 1;
118 lp->d_partitions[0].p_offset = 0;
119 lp->d_partitions[0].p_size = LABELSECTOR + 1;
120 }
121
122 /*
123 * read disklabel
124 */
125 if (msg = sdreadlabel(makedev(4, (hd->hp_unit<<3)), sdstrategy, lp)) {
126 if (msg != NULL) {
127 printf("sd%d: %s\n", hd->hp_unit, msg);
128 return(0);
129 }
130 }
131
132 sc->sc_flags = SDF_ALIVE;
133 return(1);
134 }
135
136 static struct scsi_inquiry inqbuf;
137 static struct scsi_fmt_cdb inq = {
138 6,
139 CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0
140 };
141
142 static u_long capbuf[2];
143 struct scsi_fmt_cdb cap = {
144 10,
145 CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0
146 };
147
148 int
sdident(sc,hd)149 sdident(sc, hd)
150 struct sd_softc *sc;
151 struct hp_device *hd;
152 {
153 char idstr[32];
154 int unit;
155 register int ctlr, slave;
156 register int i;
157 register int tries = 10;
158
159 ctlr = hd->hp_ctlr;
160 slave = hd->hp_slave;
161 unit = sc->sc_punit;
162
163 /*
164 * See if unit exists and is a disk then read block size & nblocks.
165 */
166 while ((i = sc_test_unit_rdy(ctlr, slave, unit)) != 0) {
167 if (i < 0 || --tries < 0)
168 return (-1);
169 if (i == STS_CHECKCOND) {
170 u_char sensebuf[8];
171 struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf;
172
173 sc_request_sense(ctlr, slave, unit, sensebuf, 8);
174 if (sp->class == 7 && sp->key == 6)
175 /* drive doing an RTZ -- give it a while */
176 DELAY(1000000);
177 }
178 DELAY(1000);
179 }
180 if (scsi_immed_command(ctlr, slave, unit, &inq, (u_char *)&inqbuf,
181 sizeof(inqbuf)) ||
182 scsi_immed_command(ctlr, slave, unit, &cap, (u_char *)&capbuf,
183 sizeof(capbuf)))
184 /* doesn't exist or not a CCS device */
185 return (-1);
186
187 switch (inqbuf.type) {
188 case 0: /* disk */
189 case 4: /* WORM */
190 case 5: /* CD-ROM */
191 case 7: /* Magneto-optical */
192 break;
193 default: /* not a disk */
194 return (-1);
195 }
196 sc->sc_blks = capbuf[0];
197 sc->sc_blksize = capbuf[1];
198
199 bcopy((caddr_t)&inqbuf.vendor_id, (caddr_t)idstr, 28);
200 for (i = 27; i > 23; --i)
201 if (idstr[i] != ' ')
202 break;
203 idstr[i+1] = 0;
204 for (i = 23; i > 7; --i)
205 if (idstr[i] != ' ')
206 break;
207 idstr[i+1] = 0;
208 for (i = 7; i >= 0; --i)
209 if (idstr[i] != ' ')
210 break;
211 idstr[i+1] = 0;
212 printf("sd%d: %s %s rev %s", hd->hp_unit, idstr, &idstr[8],
213 &idstr[24]);
214
215 printf(", %d %d byte blocks\n", sc->sc_blks, sc->sc_blksize);
216 if (sc->sc_blksize != DEV_BSIZE) {
217 printf("sd%d: need %d byte blocks - drive ignored\n", unit, DEV_BSIZE);
218 return(1);
219 }
220
221 sc->sc_wpms = 32 * (60 * DEV_BSIZE / 2); /* XXX */
222 return(inqbuf.type);
223 }
224
225
226 /*
227 * Open
228 */
229
230 int
sdopen(dev,flags,mode,p)231 sdopen(dev, flags, mode, p)
232 dev_t dev;
233 int flags, mode;
234 struct proc *p;
235 {
236 register int unit = sdunit(dev);
237 register struct sd_softc *sc = &sd_softc[unit];
238
239 if (unit >= NSD)
240 return(ENXIO);
241 if ((sc->sc_flags & SDF_ALIVE) == 0 && suser(p->p_ucred, &p->p_acflag))
242 return(ENXIO);
243
244 if (sc->sc_hd->hp_dk >= 0)
245 dk_wpms[sc->sc_hd->hp_dk] = sc->sc_wpms;
246 return(0);
247 }
248
249
250 /*
251 * Close
252 */
253
254 int
sdclose(dev,flag,mode,p)255 sdclose(dev, flag, mode, p)
256 dev_t dev;
257 int flag, mode;
258 struct proc *p;
259 {
260 return(0);
261 }
262
263 /*
264 * Strategy
265 */
266
267 int
sdstrategy(bp)268 sdstrategy(bp)
269 register struct buf *bp;
270 {
271 register int unit = sdunit(bp->b_dev);
272 register int part = sdpart(bp->b_dev);
273 register struct sd_softc *sc = &sd_softc[unit];
274 register struct disklabel *lp = &sdlabel[unit];
275 register struct partition *pp = &(lp->d_partitions[part]);
276 register struct buf *dp = &sdtab[unit];
277 register daddr_t bn;
278 register int sz, s;
279
280 bn = bp->b_blkno;
281 sz = howmany(bp->b_bcount, DEV_BSIZE);
282
283 /* check that tracsfer is within a drive's partition */
284
285 if (bn < 0 || (bn + sz) > pp->p_size) {
286 sz = pp->p_size - bn;
287 if (sz == 0) {
288 bp->b_resid = bp->b_bcount;
289 goto done;
290 }
291 if (sz < 0) {
292 bp->b_error = EINVAL;
293 bp->b_flags |= B_ERROR;
294 goto done;
295 }
296 bp->b_bcount = dbtob(sz);
297 }
298
299 /* calculate LBA for transfer */
300
301 bp->b_lba = bn + pp->p_offset;
302
303 /* raise priority to block sdintr */
304
305 s = splbio();
306
307 /* call disksort to sort request into drive queue */
308
309 disksort(dp, bp);
310
311 if (dp->b_active == 0) { /* */
312 dp->b_active = 1;
313 sdustart(unit);
314 }
315
316 /* lower priority */
317
318 splx(s);
319
320 return;
321
322 done:
323 biodone(bp);
324 }
325
326 int
sdustart(unit)327 sdustart(unit)
328 register int unit;
329 {
330 register struct sd_softc *sc = &sd_softc[unit];
331 register struct hp_device *hp = sc->sc_hd;
332 register struct scsi_queue *dq = &sc->sc_dq;
333 register struct buf *bp = sdtab[unit].b_actf;
334 register struct scsi_fmt_cdb *cmd;
335
336 cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
337 *(int *)(&cmd->cdb[2]) = bp->b_lba;
338 *(u_short *)(&cmd->cdb[7]) = howmany(bp->b_bcount, DEV_BSIZE);
339
340 dq->dq_cdb = cmd;
341 dq->dq_bp = bp;
342 dq->dq_flags = DQ_DISCONNECT; /* SCSI Disconnect */
343
344 if (screq(dq))
345 sdstart(unit);
346 }
347
348 int
sdstart(unit)349 sdstart(unit)
350 register int unit;
351 {
352 register struct sd_softc *sc = &sd_softc[unit];
353 register struct hp_device *hp = sc->sc_hd;
354
355 if (hp->hp_dk >= 0) {
356 dk_busy |= 1 << hp->hp_dk;
357 }
358
359 scstart(hp->hp_ctlr);
360 }
361
362
363 /*
364 * Return:
365 * 0 if not really an error
366 * <0 if we should do a retry
367 * >0 if a fatal error
368 */
369 static int
sderror(unit,sc,hp,stat)370 sderror(unit, sc, hp, stat)
371 int unit, stat;
372 register struct sd_softc *sc;
373 register struct hp_device *hp;
374 {
375 int cond = 1;
376
377 sdsense[unit].status = stat;
378 if (stat & STS_CHECKCOND) {
379 struct scsi_xsense *sp;
380
381 sc_request_sense(hp->hp_ctlr, hp->hp_slave,
382 sc->sc_punit, sdsense[unit].sense,
383 sizeof(sdsense[unit].sense));
384 sp = (struct scsi_xsense *)sdsense[unit].sense;
385 printf("sd%d: scsi sense class %d, code %d", unit,
386 sp->class, sp->code);
387 if (sp->class == 7) {
388 printf(", key %d", sp->key);
389 if (sp->valid)
390 printf(", blk %d", *(int *)&sp->info1);
391 switch (sp->key) {
392 /* no sense, try again */
393 case 0:
394 cond = -1;
395 break;
396 /* recovered error, not a problem */
397 case 1:
398 cond = 0;
399 break;
400 }
401 }
402 printf("\n");
403 }
404 return(cond);
405 }
406
407 /*
408 * Interrupt
409 */
410
411 int
sdintr(unit,stat)412 sdintr(unit, stat)
413 register int unit;
414 int stat;
415 {
416 register struct sd_softc *sc = &sd_softc[unit];
417 register struct hp_device *hp = sc->sc_hd;
418 register struct scsi_queue *dq = &sc->sc_dq;
419 register struct buf *bp = dq->dq_bp;
420 int cond;
421
422 if (stat == SC_IO_TIMEOUT) {
423 printf("sdintr: sd%d timeout error\n", unit, stat);
424 }
425
426 if (hp->hp_dk >= 0) {
427 dk_busy &=~ (1 << hp->hp_dk);
428 if (stat == 0) {
429 ++dk_seek[hp->hp_dk];
430 ++dk_xfer[hp->hp_dk];
431 dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
432 }
433 }
434
435 if (bp->b_flags & B_READ) {
436 sd_iostat[unit].imin = min(dq->dq_imin, sd_iostat[unit].imin);
437 if (dq->dq_imax > sd_iostat[unit].imax) {
438 sd_iostat[unit].imax = dq->dq_imax;
439 #ifdef SD_IOSTAT
440 printf("sdintr: sd%d INPUT MAX = %d, MIN = %d\n",
441 unit, sd_iostat[unit].imax, sd_iostat[unit].imin);
442 #endif
443 }
444 } else {
445 sd_iostat[unit].omin = min(dq->dq_omin, sd_iostat[unit].omin);
446 if (dq->dq_omax > sd_iostat[unit].omax) {
447 sd_iostat[unit].omax = dq->dq_omax;
448 #ifdef SD_IOSTAT
449 printf("sdintr: sd%d OUTPUT MAX = %d, MIN = %d\n",
450 unit, sd_iostat[unit].omax, sd_iostat[unit].omin);
451 #endif
452 }
453 }
454
455 if (stat != 0) {
456 if (stat > 0) {
457 #ifdef DEBUGPRINT
458 dbgprintall();
459 printf("\n");
460 #endif
461 cond = sderror(unit, sc, hp, stat);
462 if (cond) {
463 if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {
464 sdstart(unit);
465 return;
466 }
467 }
468 } else {
469 if (sdtab[unit].b_errcnt++ < SDRETRY) {
470 printf("sdintr: sd%d restart IO request\n", unit);
471 sdstart(unit);
472 return;
473 }
474 }
475 bp->b_flags |= B_ERROR;
476 bp->b_error = EIO;
477 }
478
479 sdtab[unit].b_errcnt = 0;
480 sdtab[unit].b_actf = bp->b_actf;
481
482 bp->b_resid = 0;
483
484 biodone(bp);
485
486 scfree(dq);
487
488 if (sdtab[unit].b_actf) {
489 sdustart(unit);
490 } else {
491 sdtab[unit].b_active = 0;
492 }
493 }
494
495
496 /*
497 * RAW Device Routines
498 */
499
500 int
sdread(dev,uio,flags)501 sdread(dev, uio, flags)
502 dev_t dev;
503 struct uio *uio;
504 int flags;
505 {
506 register int unit = sdunit(dev);
507
508 return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));
509 }
510
511 int
sdwrite(dev,uio,flags)512 sdwrite(dev, uio, flags)
513 dev_t dev;
514 struct uio *uio;
515 int flags;
516 {
517 register int unit = sdunit(dev);
518
519 return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));
520 }
521
522 int
sdioctl(dev,cmd,data,flag,p)523 sdioctl(dev, cmd, data, flag, p)
524 dev_t dev;
525 int cmd;
526 caddr_t data;
527 int flag;
528 struct proc *p;
529 {
530 int unit = sdunit(dev);
531 register struct sd_softc *sc = &sd_softc[unit];
532 register struct disklabel *lp = &sdlabel[unit];
533 int error = 0;
534
535 switch (cmd) {
536
537 case DIOCGDINFO:
538 *(struct disklabel *)data = *lp;
539 break;
540
541 case DIOCGPART:
542 ((struct partinfo *)data)->disklab = lp;
543 ((struct partinfo *)data)->part =
544 &lp->d_partitions[sdpart(dev)];
545 break;
546
547 case DIOCWLABEL:
548 case DIOCSDINFO:
549 case DIOCWDINFO:
550 break;
551
552 default:
553 error = ENOTTY;
554 break;
555 }
556 return (error);
557 }
558
559
560 /*
561 * Size
562 */
563
564 int
sdsize(dev)565 sdsize(dev)
566 dev_t dev;
567 {
568 register int unit = sdunit(dev);
569 register struct sd_softc *sc = &sd_softc[unit];
570
571 if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
572 return(-1);
573
574 return(sdlabel[unit].d_partitions[sdpart(dev)].p_size);
575 }
576
577
578 /*
579 * Dump
580 */
581
582 int
sddump(dev)583 sddump(dev)
584 dev_t dev;
585 {
586 }
587
588 /*
589 * Disk Subs
590 */
591
592 /*
593 * Attempt to read a disk label from a device
594 * using the indicated stategy routine.
595 * The label must be partly set up before this:
596 * secpercyl and anything required in the strategy routine
597 * (e.g., sector size) must be filled in before calling us.
598 * Returns null on success and an error string on failure.
599 */
600 char *
sdreadlabel(dev,strat,lp)601 sdreadlabel(dev, strat, lp)
602 dev_t dev;
603 int (*strat)();
604 register struct disklabel *lp;
605 {
606 register struct buf *bp;
607 struct disklabel *dlp;
608 char *msg = NULL;
609
610 if (lp->d_secperunit == 0)
611 lp->d_secperunit = 0x1fffffff;
612 lp->d_npartitions = 1;
613 if (lp->d_partitions[0].p_size == 0)
614 lp->d_partitions[0].p_size = 0x1fffffff;
615 lp->d_partitions[0].p_offset = 0;
616
617 bp = geteblk((int)lp->d_secsize);
618 bp->b_dev = dev;
619 bp->b_blkno = LABELSECTOR;
620 bp->b_bcount = lp->d_secsize;
621 bp->b_flags = B_BUSY | B_READ;
622 (*strat)(bp);
623 if (biowait(bp)) {
624 msg = "I/O error";
625 } else {
626 for (dlp = (struct disklabel *)bp->b_un.b_addr;
627 dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
628 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
629 if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
630 if (msg == NULL)
631 msg = "no disk label";
632 } else if (dlp->d_npartitions > MAXPARTITIONS ||
633 dkcksum(dlp) != 0)
634 msg = "disk label corrupted";
635 else {
636 *lp = *dlp;
637 msg = NULL;
638 break;
639 }
640 }
641 }
642 bp->b_flags = B_INVAL | B_AGE;
643 brelse(bp);
644 return (msg);
645 }
646
647 #ifdef notyet
648
649 /*
650 * Checksum routine for OMRON native disklabel
651 */
652
653 #define OMRON_LBLSIZE 512
654
655 u_short
omcksum(omp)656 omcksum(omp)
657 register char *omp;
658 {
659 register u_short *start, *end;
660 register u_short sum = 0;
661
662 start = (u_short *) omp;
663 end = (u_short *) &start[(OMRON_LBLSIZE/sizeof(u_short) - 1)];
664 while (start < end)
665 sum ^= *start++;
666
667 printf("omcksum: saved ... 0x%s\n", hexstr(*end, 4));
668 printf("omcksum: calced ... 0x%s\n", hexstr(sum, 4));
669
670 return (sum);
671 }
672
673 /*
674 * Write disk label back to device after modification.
675 */
sdwritelabel(dev,strat,lp)676 sdwritelabel(dev, strat, lp)
677 dev_t dev;
678 int (*strat)();
679 register struct disklabel *lp;
680 {
681 struct buf *bp;
682 struct disklabel *dlp;
683 int labelpart;
684 int error = 0;
685
686 labelpart = sdpart(dev);
687 if (lp->d_partitions[labelpart].p_offset != 0) {
688 if (lp->d_partitions[0].p_offset != 0)
689 return (EXDEV); /* not quite right */
690 labelpart = 0;
691 }
692
693 bp = geteblk((int)lp->d_secsize);
694 bp->b_dev = makedev(major(dev), sdminor(sdunit(dev), labelpart));
695 bp->b_blkno = LABELSECTOR;
696 bp->b_bcount = lp->d_secsize;
697 bp->b_flags = B_READ;
698 (*strat)(bp);
699 if (error = biowait(bp))
700 goto done;
701
702 for (dlp = (struct disklabel *)bp->b_un.b_addr;
703 dlp <= (struct disklabel *)
704 (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
705 dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
706 if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
707 dkcksum(dlp) == 0) {
708 omcksum(bp->b_un.b_addr);
709 /*
710 *dlp = *lp;
711 bp->b_flags = B_WRITE;
712 (*strat)(bp);
713 error = biowait(bp);
714 goto done;
715 */
716 }
717 }
718 error = ESRCH;
719 done:
720 brelse(bp);
721 return (error);
722 }
723 #endif
724
725 #endif
726