⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hd.c.txt

📁 Linux块设备驱动分析与模拟实现
💻 TXT
📖 第 1 页 / 共 2 页
字号:
401                 do_hd_request();
402         }
403         return;
404 }
405 
406 static void recal_intr(void)
407 {
408         if (win_result())
409                 bad_rw_intr();
410         do_hd_request();
411 }
412 
413 /*
414  * This is another of the error-routines I don't know what to do with. The
415  * best idea seems to just set reset, and start all over again.
416  */
417 static void hd_times_out(void)
418 {
419         DEVICE_INTR = NULL;
420         sti();
421         reset = 1;
422         if (!CURRENT)
423                 return;
424         printk(KERN_DEBUG "HD timeout\n");
425         cli();
426         if (++CURRENT->errors >= MAX_ERRORS) {
427 #ifdef DEBUG
428                 printk("hd : too many errors.\n");
429 #endif
430                 end_request(0);
431         }
432 
433         do_hd_request();
434 }
435 
436 /*
437  * The driver has been modified to enable interrupts a bit more: in order to
438  * do this we first (a) disable the timeout-interrupt and (b) clear the
439  * device-interrupt. This way the interrupts won't mess with out code (the
440  * worst that can happen is that an unexpected HD-interrupt comes in and
441  * sets the "reset" variable and starts the timer)
442  */
443 static void do_hd_request(void)
444 {
445         unsigned int block,dev;
446         unsigned int sec,head,cyl,track;
447         unsigned int nsect;
448 
449         if (CURRENT && CURRENT->dev < 0) return;
450 
451         if (DEVICE_INTR)
452                 return;
453 repeat:
454         timer_active &= ~(1<<HD_TIMER);
455         sti();
456         INIT_REQUEST;
457         dev = MINOR(CURRENT->dev);
458         block = CURRENT->sector;
459         nsect = CURRENT->nr_sectors;
460         if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
461 #ifdef DEBUG
462                 printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
463                         block, hd[dev].nr_sects);
464 #endif
465                 end_request(0);
466                 goto repeat;
467         }
468         block += hd[dev].start_sect;
469         dev >>= 6;
470         sec = block % hd_info[dev].sect + 1;
471         track = block / hd_info[dev].sect;
472         head = track % hd_info[dev].head;
473         cyl = track / hd_info[dev].head;
474 #ifdef DEBUG
475         printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
476                 dev, cyl, head, sec, CURRENT->buffer);
477 #endif
478         cli();
479         if (reset) {
480                 int i;
481 
482                 for (i=0; i < NR_HD; i++)
483                         recalibrate[i] = 1;
484                 reset_hd();
485                 sti();
486                 return;
487         }
488         if (recalibrate[dev]) {
489                 recalibrate[dev] = 0;
490                 hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
491                 if (reset)
492                         goto repeat;
493                 sti();
494                 return;
495         }       
496         if (CURRENT->cmd == WRITE) {
497                 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
498                 if (reset)
499                         goto repeat;
500                 if (wait_DRQ()) {
501                         printk("HD: do_hd_request: no DRQ\n");
502                         bad_rw_intr();
503                         goto repeat;
504                 }
505                 outsw(HD_DATA,CURRENT->buffer,256);
506                 sti();
507                 return;
508         }
509         if (CURRENT->cmd == READ) {
510                 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
511                 if (reset)
512                         goto repeat;
513                 sti();
514                 return;
515         }
516         panic("unknown hd-command");
517 }
518 
519 static int hd_ioctl(struct inode * inode, struct file * file,
520         unsigned int cmd, unsigned long arg)
521 {
522         struct hd_geometry *loc = (struct hd_geometry *) arg;
523         int dev, err;
524 
525         if (!inode)
526                 return -EINVAL;
527         dev = MINOR(inode->i_rdev) >> 6;
528         if (dev >= NR_HD)
529                 return -EINVAL;
530         switch (cmd) {
531                 case HDIO_GETGEO:
532                         if (!loc)  return -EINVAL;
533                         err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
534                         if (err)
535                                 return err;
536                         put_fs_byte(hd_info[dev].head,
537                                 (char *) &loc->heads);
538                         put_fs_byte(hd_info[dev].sect,
539                                 (char *) &loc->sectors);
540                         put_fs_word(hd_info[dev].cyl,
541                                 (short *) &loc->cylinders);
542                         put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
543                                 (long *) &loc->start);
544                         return 0;
545                 case BLKGETSIZE:   /* Return device size */
546                         if (!arg)  return -EINVAL;
547                         err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
548                         if (err)
549                                 return err;
550                         put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects,
551                                 (long *) arg);
552                         return 0;
553                 case BLKFLSBUF:
554                         if(!suser())  return -EACCES;
555                         if(!inode->i_rdev) return -EINVAL;
556                         fsync_dev(inode->i_rdev);
557                         invalidate_buffers(inode->i_rdev);
558                         return 0;
559 
560                 case BLKRRPART: /* Re-read partition tables */
561                         return revalidate_hddisk(inode->i_rdev, 1);
562                 RO_IOCTLS(inode->i_rdev,arg);
563                 default:
564                         return -EINVAL;
565         }
566 }
567 
568 static int hd_open(struct inode * inode, struct file * filp)
569 {
570         int target;
571         target =  DEVICE_NR(MINOR(inode->i_rdev));
572 
573         while (busy[target])
574                 sleep_on(&busy_wait);
575         access_count[target]++;
576         return 0;
577 }
578 
579 /*
580  * Releasing a block device means we sync() it, so that it can safely
581  * be forgotten about...
582  */
583 static void hd_release(struct inode * inode, struct file * file)
584 {
585         int target;
586         sync_dev(inode->i_rdev);
587 
588         target =  DEVICE_NR(MINOR(inode->i_rdev));
589         access_count[target]--;
590 
591 }
592 
593 static void hd_geninit(void);
594 
595 static struct gendisk hd_gendisk = {
596         MAJOR_NR,       /* Major number */      
597         "hd",           /* Major name */
598         6,              /* Bits to shift to get real from partition */
599         1 << 6,         /* Number of partitions per real */
600         MAX_HD,         /* maximum number of real */
601         hd_geninit,     /* init function */
602         hd,             /* hd struct */
603         hd_sizes,       /* block sizes */
604         0,              /* number */
605         (void *) hd_info,       /* internal */
606         NULL            /* next */
607 };
608         
609 static void hd_interrupt(int unused)
610 {
611         void (*handler)(void) = DEVICE_INTR;
612 
613         DEVICE_INTR = NULL;
614         timer_active &= ~(1<<HD_TIMER);
615         if (!handler)
616                 handler = unexpected_hd_interrupt;
617         handler();
618         sti();
619 }
620 
621 /*
622  * This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
623  * means we run the IRQ-handler with interrupts disabled: this is bad for
624  * interrupt latency, but anything else has led to problems on some
625  * machines...
626  *
627  * We enable interrupts in some of the routines after making sure it's
628  * safe.
629  */
630 static struct sigaction hd_sigaction = {
631         hd_interrupt,
632         0,
633         SA_INTERRUPT,
634         NULL
635 };
636 
637 static void hd_geninit(void)
638 {
639         int drive, i;
640         extern struct drive_info drive_info;
641         unsigned char *BIOS = (unsigned char *) &drive_info;
642         int cmos_disks;
643 
644         if (!NR_HD) {      
645                 for (drive=0 ; drive<2 ; drive++) {
646                         hd_info[drive].cyl = *(unsigned short *) BIOS;
647                         hd_info[drive].head = *(2+BIOS);
648                         hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
649                         hd_info[drive].ctl = *(8+BIOS);
650                         hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
651                         hd_info[drive].sect = *(14+BIOS);
652                         BIOS += 16;
653                 }
654 
655         /*
656                 We querry CMOS about hard disks : it could be that 
657                 we have a SCSI/ESDI/etc controller that is BIOS
658                 compatable with ST-506, and thus showing up in our
659                 BIOS table, but not register compatable, and therefore
660                 not present in CMOS.
661 
662                 Furthurmore, we will assume that our ST-506 drives
663                 <if any> are the primary drives in the system, and 
664                 the ones reflected as drive 1 or 2.
665 
666                 The first drive is stored in the high nibble of CMOS
667                 byte 0x12, the second in the low nibble.  This will be
668                 either a 4 bit drive type or 0xf indicating use byte 0x19 
669                 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
670 
671                 Needless to say, a non-zero value means we have 
672                 an AT controller hard disk for that drive.
673 
674                 
675         */
676 
677                 if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
678                         if (cmos_disks & 0x0f)
679                                 NR_HD = 2;
680                         else
681                                 NR_HD = 1;
682         }
683         i = NR_HD;
684         while (i-- > 0) {
685                 hd[i<<6].nr_sects = 0;
686                 if (hd_info[i].head > 16) {
687                         printk("hd.c: ST-506 interface disk with more than 16 heads detected,\n");
688                         printk("  probably due to non-standard sector translation. Giving up.\n");
689                         printk("  (disk %d: cyl=%d, sect=%d, head=%d)\n", i,
690                                 hd_info[i].cyl,
691                                 hd_info[i].sect,
692                                 hd_info[i].head);
693                         if (i+1 == NR_HD)
694                                 NR_HD--;
695                         continue;
696                 }
697                 hd[i<<6].nr_sects = hd_info[i].head*
698                                 hd_info[i].sect*hd_info[i].cyl;
699         }
700         if (NR_HD) {
701                 if (irqaction(HD_IRQ,&hd_sigaction)) {
702                         printk("hd.c: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
703                         NR_HD = 0;
704                 }
705         }
706         hd_gendisk.nr_real = NR_HD;
707 
708         for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024;
709         blksize_size[MAJOR_NR] = hd_blocksizes;
710 }
711 
712 static struct file_operations hd_fops = {
713         NULL,                   /* lseek - default */
714         block_read,             /* read - general block-dev read */
715         block_write,            /* write - general block-dev write */
716         NULL,                   /* readdir - bad */
717         NULL,                   /* select */
718         hd_ioctl,               /* ioctl */
719         NULL,                   /* mmap */
720         hd_open,                /* open */
721         hd_release,             /* release */
722         block_fsync             /* fsync */
723 };
724 
725 unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
726 {
727         if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
728                 printk("Unable to get major %d for harddisk\n",MAJOR_NR);
729                 return mem_start;
730         }
731         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
732         read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
733         hd_gendisk.next = gendisk_head;
734         gendisk_head = &hd_gendisk;
735         timer_table[HD_TIMER].fn = hd_times_out;
736         return mem_start;
737 }
738 
739 #define DEVICE_BUSY busy[target]
740 #define USAGE access_count[target]
741 #define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
742 /* We assume that the the bios parameters do not change, so the disk capacity
743    will not change */
744 #undef MAYBE_REINIT
745 #define GENDISK_STRUCT hd_gendisk
746 
747 /*
748  * This routine is called to flush all partitions and partition tables
749  * for a changed scsi disk, and then re-read the new partition table.
750  * If we are revalidating a disk because of a media change, then we
751  * enter with usage == 0.  If we are using an ioctl, we automatically have
752  * usage == 1 (we need an open channel to use an ioctl :-), so this
753  * is our limit.
754  */
755 static int revalidate_hddisk(int dev, int maxusage)
756 {
757         int target, major;
758         struct gendisk * gdev;
759         int max_p;
760         int start;
761         int i;
762 
763         target =  DEVICE_NR(MINOR(dev));
764         gdev = &GENDISK_STRUCT;
765 
766         cli();
767         if (DEVICE_BUSY || USAGE > maxusage) {
768                 sti();
769                 return -EBUSY;
770         };
771         DEVICE_BUSY = 1;
772         sti();
773 
774         max_p = gdev->max_p;
775         start = target << gdev->minor_shift;
776         major = MAJOR_NR << 8;
777 
778         for (i=max_p - 1; i >=0 ; i--) {
779                 sync_dev(major | start | i);
780                 invalidate_inodes(major | start | i);
781                 invalidate_buffers(major | start | i);
782                 gdev->part[start+i].start_sect = 0;
783                 gdev->part[start+i].nr_sects = 0;
784         };
785 
786 #ifdef MAYBE_REINIT
787         MAYBE_REINIT;
788 #endif
789 
790         gdev->part[start].nr_sects = CAPACITY;
791         resetup_one_dev(gdev, target);
792 
793         DEVICE_BUSY = 0;
794         wake_up(&busy_wait);
795         return 0;
796 }
797 
798 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -