xref: /original-bsd/sys/luna68k/dev/sd.c (revision 4e889fb4)
1 /*
2  * Copyright (c) 1992 OMRON Corporation.
3  * Copyright (c) 1992 The Regents of the University of California.
4  * 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	7.5 (Berkeley) 12/31/92
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/scsireg.h>
34 #include <luna68k/dev/scsivar.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
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
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 = scsi_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 			scsi_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
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  * Strategy
252  */
253 
254 int
255 sdstrategy(bp)
256 	register struct buf *bp;
257 {
258 	register int unit = sdunit(bp->b_dev);
259 	register int part = sdpart(bp->b_dev);
260 	register struct sd_softc *sc = &sd_softc[unit];
261 	register struct disklabel *lp = &sdlabel[unit];
262 	register struct partition *pp = &(lp->d_partitions[part]);
263 	register struct buf *dp = &sdtab[unit];
264 	register daddr_t bn;
265 	register int sz, s;
266 
267 #ifdef DEBUG
268 	printf("sdstrategy: bp->b_blkno = %d, bp->bcount = %d\n",
269 	       bp->b_blkno, bp->b_bcount);
270 #endif
271 	bn = bp->b_blkno;
272 	sz = howmany(bp->b_bcount, DEV_BSIZE);
273 
274 	/* check that tracsfer is within a drive's partition */
275 
276 	if (bn < 0 || (bn + sz) > pp->p_size) {
277 		sz = pp->p_size - bn;
278 		if (sz == 0) {
279 			bp->b_resid = bp->b_bcount;
280 			goto done;
281 		}
282 		if (sz < 0) {
283 			bp->b_error = EINVAL;
284 			bp->b_flags |= B_ERROR;
285 			goto done;
286 		}
287 		bp->b_bcount = dbtob(sz);
288 	}
289 
290 	/* calculate LBA for transfer */
291 
292 	bp->b_lba = bn + pp->p_offset;
293 
294 	/* raise priority to block sdintr */
295 
296 	s = splbio();
297 
298 	/* call disksort to sort request into drive queue */
299 
300 	disksort(dp, bp);
301 
302 #ifdef DEBUG
303 	printf("sdstrategy: dp->b_active = %d\n", dp->b_active);
304 #endif
305 	if (dp->b_active == 0) {			/*  */
306 		dp->b_active = 1;
307 		sdustart(unit);
308 	}
309 
310 	/* lower priority */
311 
312 	splx(s);
313 
314 	return;
315 
316 done:
317 	biodone(bp);
318 }
319 
320 int
321 sdustart(unit)
322 	register int unit;
323 {
324 	register struct sd_softc *sc = &sd_softc[unit];
325 	register struct hp_device *hp = sc->sc_hd;
326 	register struct scsi_queue *dq = &sc->sc_dq;
327 	register struct buf *bp = sdtab[unit].b_actf;
328 	register struct scsi_fmt_cdb *cmd;
329 
330 	cmd = bp->b_flags & B_READ? &sd_read_cmd : &sd_write_cmd;
331 	*(int *)(&cmd->cdb[2]) = bp->b_lba;
332 	*(u_short *)(&cmd->cdb[7]) = howmany(bp->b_bcount, DEV_BSIZE);
333 
334 	dq->dq_cdb   = cmd;
335 	dq->dq_bp    = bp;
336 	dq->dq_flags = DQ_DISCONNECT;	/* SCSI Disconnect */
337 
338 	if (screq(dq))
339 		sdstart(unit);
340 }
341 
342 int
343 sdstart(unit)
344 	register int unit;
345 {
346 	register struct sd_softc *sc = &sd_softc[unit];
347 	register struct hp_device *hp = sc->sc_hd;
348 
349 	if (hp->hp_dk >= 0) {
350 		dk_busy |= 1 << hp->hp_dk;
351 	}
352 
353 	scstart(hp->hp_ctlr);
354 }
355 
356 
357 /*
358  * Return:
359  *	0	if not really an error
360  *	<0	if we should do a retry
361  *	>0	if a fatal error
362  */
363 static int
364 sderror(unit, sc, hp, stat)
365 	int unit, stat;
366 	register struct sd_softc *sc;
367 	register struct hp_device *hp;
368 {
369 	int cond = 1;
370 
371 	sdsense[unit].status = stat;
372 	if (stat & STS_CHECKCOND) {
373 		struct scsi_xsense *sp;
374 
375 		scsi_request_sense(hp->hp_ctlr, hp->hp_slave,
376 				   sc->sc_punit, sdsense[unit].sense,
377 				   sizeof(sdsense[unit].sense));
378 		sp = (struct scsi_xsense *)sdsense[unit].sense;
379 		printf("sd%d: scsi sense class %d, code %d", unit,
380 			sp->class, sp->code);
381 		if (sp->class == 7) {
382 			printf(", key %d", sp->key);
383 			if (sp->valid)
384 				printf(", blk %d", *(int *)&sp->info1);
385 			switch (sp->key) {
386 			/* no sense, try again */
387 			case 0:
388 				cond = -1;
389 				break;
390 			/* recovered error, not a problem */
391 			case 1:
392 				cond = 0;
393 				break;
394 			}
395 		}
396 		printf("\n");
397 	}
398 	return(cond);
399 }
400 
401 /*
402  * Interrupt
403  */
404 
405 int
406 sdintr(unit, stat)
407 	register int unit;
408 	int stat;
409 {
410 	register struct sd_softc *sc = &sd_softc[unit];
411 	register struct hp_device *hp = sc->sc_hd;
412 	register struct scsi_queue *dq = &sc->sc_dq;
413 	register struct buf *bp = dq->dq_bp;
414 	int cond;
415 
416 #ifdef DEBUG
417 	printf("sdintr(unit = %d, stat = %d)\n", unit, stat);
418 #endif
419 
420 	if (stat == SC_IO_TIMEOUT) {
421 		printf("sdintr: sd%d timeout error\n", unit, stat);
422 	}
423 
424 	if (hp->hp_dk >= 0) {
425 		dk_busy &=~ (1 << hp->hp_dk);
426 		if (stat == 0) {
427 			++dk_seek[hp->hp_dk];
428 			++dk_xfer[hp->hp_dk];
429 			dk_wds[hp->hp_dk] += bp->b_bcount >> 6;
430 		}
431 	}
432 
433 	if (bp->b_flags & B_READ) {
434 		sd_iostat[unit].imin = min(dq->dq_imin, sd_iostat[unit].imin);
435 		if (dq->dq_imax > sd_iostat[unit].imax) {
436 			sd_iostat[unit].imax = dq->dq_imax;
437 #ifdef SD_IOSTAT
438 			printf("sdintr: sd%d  INPUT	MAX = %d, MIN = %d\n",
439 			       unit, sd_iostat[unit].imax, sd_iostat[unit].imin);
440 #endif
441 		}
442 	} else {
443 		sd_iostat[unit].omin = min(dq->dq_omin, sd_iostat[unit].omin);
444 		if (dq->dq_omax > sd_iostat[unit].omax) {
445 			sd_iostat[unit].omax = dq->dq_omax;
446 #ifdef SD_IOSTAT
447 			printf("sdintr: sd%d  OUTPUT	MAX = %d, MIN = %d\n",
448 			       unit, sd_iostat[unit].omax, sd_iostat[unit].omin);
449 #endif
450 		}
451 	}
452 
453 	if (stat != 0) {
454 		if (stat > 0) {
455 #ifdef DEBUGPRINT
456 			dbgprintall();
457 			printf("\n");
458 #endif
459 			cond = sderror(unit, sc, hp, stat);
460 			if (cond) {
461 				if (cond < 0 && sdtab[unit].b_errcnt++ < SDRETRY) {
462 					sdstart(unit);
463 					return;
464 				}
465 			}
466 		} else {
467 			if (sdtab[unit].b_errcnt++ < SDRETRY) {
468 				printf("sdintr: sd%d restart IO request\n", unit);
469 				sdstart(unit);
470 				return;
471 			}
472 		}
473 		bp->b_flags |= B_ERROR;
474 		bp->b_error = EIO;
475 	}
476 
477 	sdtab[unit].b_errcnt = 0;
478 	sdtab[unit].b_actf = bp->b_actf;
479 
480 	bp->b_resid = 0;
481 
482 	biodone(bp);
483 
484 	scfree(dq);
485 
486 	if (sdtab[unit].b_actf) {
487 		sdustart(unit);
488 	} else {
489 		sdtab[unit].b_active = 0;
490 	}
491 }
492 
493 
494 /*
495  * RAW Device Routines
496  */
497 
498 int
499 sdread(dev, uio, flags)
500 	dev_t dev;
501 	struct uio *uio;
502 	int flags;
503 {
504 	register int unit = sdunit(dev);
505 
506 	return (physio(sdstrategy, NULL, dev, B_READ, minphys, uio));
507 }
508 
509 int
510 sdwrite(dev, uio, flags)
511 	dev_t dev;
512 	struct uio *uio;
513 	int flags;
514 {
515 	register int unit = sdunit(dev);
516 
517 	return (physio(sdstrategy, NULL, dev, B_WRITE, minphys, uio));
518 }
519 
520 int
521 sdioctl(dev, cmd, data, flag, p)
522 	dev_t dev;
523 	int cmd;
524 	caddr_t data;
525 	int flag;
526 	struct proc *p;
527 {
528 	int unit = sdunit(dev);
529 	register struct sd_softc *sc = &sd_softc[unit];
530 	register struct disklabel *lp = &sdlabel[unit];
531 	int error = 0;
532 
533 	switch (cmd) {
534 
535 	case DIOCGDINFO:
536 		*(struct disklabel *)data = *lp;
537 		break;
538 
539 	case DIOCGPART:
540 		((struct partinfo *)data)->disklab = lp;
541 		((struct partinfo *)data)->part =
542 		    &lp->d_partitions[sdpart(dev)];
543 		break;
544 
545         case DIOCWLABEL:
546         case DIOCSDINFO:
547         case DIOCWDINFO:
548 		break;
549 
550 	default:
551 		error = ENOTTY;
552 		break;
553 	}
554 	return (error);
555 }
556 
557 
558 /*
559  * Size
560  */
561 
562 int
563 sdsize(dev)
564 	dev_t dev;
565 {
566 	register int unit = sdunit(dev);
567 	register struct sd_softc *sc = &sd_softc[unit];
568 
569 	if (unit >= NSD || (sc->sc_flags & SDF_ALIVE) == 0)
570 		return(-1);
571 
572 	return(sdlabel[unit].d_partitions[sdpart(dev)].p_size);
573 }
574 
575 
576 /*
577  * Dump
578  */
579 
580 int
581 sddump(dev)
582 	dev_t dev;
583 {
584 }
585 
586 /*
587  * Disk Subs
588  */
589 
590 /*
591  * Attempt to read a disk label from a device
592  * using the indicated stategy routine.
593  * The label must be partly set up before this:
594  * secpercyl and anything required in the strategy routine
595  * (e.g., sector size) must be filled in before calling us.
596  * Returns null on success and an error string on failure.
597  */
598 char *
599 sdreadlabel(dev, strat, lp)
600 	dev_t dev;
601 	int (*strat)();
602 	register struct disklabel *lp;
603 {
604 	register struct buf *bp;
605 	struct disklabel *dlp;
606 	char *msg = NULL;
607 
608 	if (lp->d_secperunit == 0)
609 		lp->d_secperunit = 0x1fffffff;
610 	lp->d_npartitions = 1;
611 	if (lp->d_partitions[0].p_size == 0)
612 		lp->d_partitions[0].p_size = 0x1fffffff;
613 	lp->d_partitions[0].p_offset = 0;
614 
615 	bp = geteblk((int)lp->d_secsize);
616 	bp->b_dev = dev;
617 	bp->b_blkno = LABELSECTOR;
618 	bp->b_bcount = lp->d_secsize;
619 	bp->b_flags = B_BUSY | B_READ;
620 	(*strat)(bp);
621 	if (biowait(bp)) {
622 		msg = "I/O error";
623 	} else {
624 		for (dlp = (struct disklabel *)bp->b_un.b_addr;
625 		     dlp <= (struct disklabel *)(bp->b_un.b_addr+DEV_BSIZE-sizeof(*dlp));
626 		     dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
627 			if (dlp->d_magic != DISKMAGIC || dlp->d_magic2 != DISKMAGIC) {
628 				if (msg == NULL)
629 					msg = "no disk label";
630 			} else if (dlp->d_npartitions > MAXPARTITIONS ||
631 				   dkcksum(dlp) != 0)
632 				msg = "disk label corrupted";
633 			else {
634 				*lp = *dlp;
635 				msg = NULL;
636 				break;
637 			}
638 		}
639 	}
640 	bp->b_flags = B_INVAL | B_AGE;
641 	brelse(bp);
642 	return (msg);
643 }
644 
645 #ifdef notyet
646 
647 /*
648  * Checksum routine for OMRON native disklabel
649  */
650 
651 #define	OMRON_LBLSIZE	512
652 
653 u_short
654 omcksum(omp)
655 	register char *omp;
656 {
657 	register u_short *start, *end;
658 	register u_short sum = 0;
659 
660 	start = (u_short *) omp;
661 	end = (u_short *) &start[(OMRON_LBLSIZE/sizeof(u_short) - 1)];
662 	while (start < end)
663 		sum ^= *start++;
664 
665 	printf("omcksum: saved  ... 0x%s\n", hexstr(*end, 4));
666 	printf("omcksum: calced ... 0x%s\n", hexstr(sum, 4));
667 
668 	return (sum);
669 }
670 
671 /*
672  * Write disk label back to device after modification.
673  */
674 sdwritelabel(dev, strat, lp)
675 	dev_t dev;
676 	int (*strat)();
677 	register struct disklabel *lp;
678 {
679 	struct buf *bp;
680 	struct disklabel *dlp;
681 	int labelpart;
682 	int error = 0;
683 
684 	labelpart = sdpart(dev);
685 	if (lp->d_partitions[labelpart].p_offset != 0) {
686 		if (lp->d_partitions[0].p_offset != 0)
687 			return (EXDEV);			/* not quite right */
688 		labelpart = 0;
689 	}
690 
691 	bp = geteblk((int)lp->d_secsize);
692 	bp->b_dev = makedev(major(dev), sdminor(sdunit(dev), labelpart));
693 	bp->b_blkno = LABELSECTOR;
694 	bp->b_bcount = lp->d_secsize;
695 	bp->b_flags = B_READ;
696 	(*strat)(bp);
697 	if (error = biowait(bp))
698 		goto done;
699 
700 	for (dlp = (struct disklabel *)bp->b_un.b_addr;
701 	    dlp <= (struct disklabel *)
702 	      (bp->b_un.b_addr + lp->d_secsize - sizeof(*dlp));
703 	    dlp = (struct disklabel *)((char *)dlp + sizeof(long))) {
704 		if (dlp->d_magic == DISKMAGIC && dlp->d_magic2 == DISKMAGIC &&
705 		    dkcksum(dlp) == 0) {
706 			omcksum(bp->b_un.b_addr);
707 /*
708 			*dlp = *lp;
709 			bp->b_flags = B_WRITE;
710 			(*strat)(bp);
711 			error = biowait(bp);
712 			goto done;
713  */
714 		}
715 	}
716 	error = ESRCH;
717 done:
718 	brelse(bp);
719 	return (error);
720 }
721 #endif
722 
723 #endif
724