Ide_driver的注册(三)
Linux内核代码之所以如此精辟,我觉得很主要的一个原因是容易让人产生健忘,这样前面说的后面联系不上,猛然回头一看的时候,很容易让人产生扑朔迷离的感觉,从而衬托出他的一种境界。当然,要说清楚这里的这个故事就得回到N年以前我们讲到的一个传说。早在ide-generic中add-host的时候我们通过层层调用最终通过request_irq申请了一个ide中断,当说到对应的中断向量是ide_intr的时候我们妥协了,说以后有用到的时候再来分析。今天总算到了他开花结果的时候了,进去开开眼界:
[ide-io.c]
753 /**
754 * ide_intr - default IDE interrupt handler
755 * @irq: interrupt number
756 * @dev_id: hwif
757 * @regs: unused weirdness from the kernel irq layer
758 *
759 * This is the default IRQ handler for the IDE layer. You should
760 * not need to override it. If you do be aware it is subtle in
761 * places
762 *
763 * hwif is the interface in the group currently performing
764 * a command. hwif->cur_dev is the drive and hwif->handler is
765 * the IRQ handler to call. As we issue a command the handlers
766 * step through multiple states, reassigning the handler to the
767 * next step in the process. Unlike a smart SCSI controller IDE
768 * expects the main processor to sequence the various transfer
769 * stages. We also manage a poll timer to catch up with most
770 * timeout situations. There are still a few where the handlers
771 * don't ever decide to give up.
772 *
773 * The handler eventually returns ide_stopped to indicate the
774 * request completed. At this point we issue the next request
775 * on the port and the process begins again.
776 */
777
778 irqreturn_t ide_intr (int irq, void *dev_id)
779 {
780 ide_hwif_t *hwif = (ide_hwif_t *)dev_id;
781 struct ide_host *host = hwif->host;
782 ide_drive_t *uninitialized_var(drive);
783 ide_handler_t *handler;
784 unsigned long flags;
785 ide_startstop_t startstop;
786 irqreturn_t irq_ret = IRQ_NONE;
787 int plug_device = 0;
788 struct request *uninitialized_var(rq_in_flight);
789
790 if (host->host_flags & IDE_HFLAG_SERIALIZE) {
791 if (hwif != host->cur_port)
792 goto out_early;
793 }
794
795 spin_lock_irqsave(&hwif->lock, flags);
796
797 if (hwif->port_ops && hwif->port_ops->test_irq &&
798 hwif->port_ops->test_irq(hwif) == 0)
799 goto out;
800
801 handler = hwif->handler;
802
803 if (handler == NULL || hwif->polling) {
804 /*
805 * Not expecting an interrupt from this drive.
806 * That means this could be:
807 * (1) an interrupt from another PCI device
808 * sharing the same PCI INT# as us.
809 * or (2) a drive just entered sleep or standby mode,
810 * and is interrupting to let us know.
811 * or (3) a spurious interrupt of unknown origin.
812 *
813 * For PCI, we cannot tell the difference,
814 * so in that case we just ignore it and hope it goes away.
815 */
816 if ((host->irq_flags & IRQF_SHARED) == 0) {
817 /*
818 * Probably not a shared PCI interrupt,
819 * so we can safely try to do something about it:
820 */
821 unexpected_intr(irq, hwif);
822 } else {
823 /*
824 * Whack the status register, just in case
825 * we have a leftover pending IRQ.
826 */
827 (void)hwif->tp_ops->read_status(hwif);
828 }
829 goto out;
830 }
831
832 drive = hwif->cur_dev;
833
834 if (!drive_is_ready(drive))
835 /*
836 * This happens regularly when we share a PCI IRQ with
837 * another device. Unfortunately, it can also happen
838 * with some buggy drives that trigger the IRQ before
839 * their status register is up to date. Hopefully we have
840 * enough advance overhead that the latter isn't a problem.
841 */
842 goto out;
843
844 hwif->handler = NULL;
845 hwif->expiry = NULL;
846 hwif->req_gen++;
847 del_timer(&hwif->timer);
848 spin_unlock(&hwif->lock);
849
850 if (hwif->port_ops && hwif->port_ops->clear_irq)
851 hwif->port_ops->clear_irq(drive);
852
853 if (drive->dev_flags & IDE_DFLAG_UNMASK)
854 local_irq_enable_in_hardirq();
855
856 /* service this interrupt, may set handler for next interrupt */
857 startstop = handler(drive);
858
859 spin_lock_irq(&hwif->lock);
860 /*
861 * Note that handler() may have set things up for another
862 * interrupt to occur soon, but it cannot happen until
863 * we exit from this routine, because it will be the
864 * same irq as is currently being serviced here, and Linux
865 * won't allow another of the same (on any CPU) until we return.
866 */
867 if (startstop == ide_stopped && hwif->polling == 0) {
868 BUG_ON(hwif->handler);
869 rq_in_flight = hwif->rq;
870 hwif->rq = NULL;
871 ide_unlock_port(hwif);
872 plug_device = 1;
873 }
874 irq_ret = IRQ_HANDLED;
875 out:
876 spin_unlock_irqrestore(&hwif->lock, flags);
877 out_early:
878 if (plug_device) {
879 ide_unlock_host(hwif->host);
880 ide_requeue_and_plug(drive, rq_in_flight);
881 }
882
883 return irq_ret;
884 }
从这段堪称和代码长度相媲美的注释来看,就足以让我们对他产生了恐惧。但是没有办法,不管前面是多大的火焰山,还是等扛过去呀。来看代码:
首先不说别的但从注释来看,这是整个ide所共享的一个中断向量。我们知道一般共享的中断向量都会有个dev_id来区分,不然岂不是乱了伦理。这里就是用hwif来区分了。
801行 handler = hwif->handler;和我们上面__ide_set_handler的450 hwif->handler= handler;相比是不是有种说不出的赤裸裸的美感呀。既然这么爽那么我们干脆就上到底把ide_intr的857行一起看了857 startstop = handler(drive); 。这个时候你也许就感叹了,哎呀我的个妈呀,原来他们是有预谋有组织的在活动啊,的确内核他就喜欢干这样的勾当。说到这其实不想再往下说了,应该说已经解释清楚了智慧一想表达的观点。但是看到精美的内核代码,还是不禁多说两句…..
844行注意一个细节,hwif->handler = NULL;因为这个中断函数是大家公共的,所以当一个任务执行完了以后hwif->handler是要被清除的,如果不清除这个向量在出现程序中803-830行所对应的这些情景的时候就会引发错误的操作,这是不允许的。
803-830行对应的情景代码的作者已经给了详细的注释,相信理解起来不算困难。
对于这个函数就说这么多了,接下来我们回到__ide_set_handler。
智慧二:
451-453典型的定时器的操作,写过linux驱动代码的不会不知到这个大名鼎鼎的timer,同样知道timer的不会不知道他应该对应的有一个timer_handle。好的,这就对头了,与刚才的情况一样,让我们继续穿越时空来到上个世纪的ide-generic初始化。在ide_init_port_data函数中调用了这么一段,相信都已经忘怀了,还是贴出他相关的一小段。
1173 init_timer(&hwif->timer);
1174 hwif->timer.function = &ide_timer_expiry;
1175 hwif->timer.data = (unsigned long)hwif;
这段代码以一种很黄很暴力的方式告诉我们,如果你的设备超时了,那么不客气我就要调用ide_timer_expiry来解决了。不知道ide_timer_expiry和武汉的城管相比谁更加不得人心,那么我们还是来进去看看吧,不入虎穴,焉得虎子….
[ide-io.c]
607 /**
608 * ide_timer_expiry - handle lack of an IDE interrupt
609 * @data: timer callback magic (hwif)
610 *
611 * An IDE command has timed out before the expected drive return
612 * occurred. At this point we attempt to clean up the current
613 * mess. If the current handler includes an expiry handler then
614 * we invoke the expiry handler, and providing it is happy the
615 * work is done. If that fails we apply generic recovery rules
616 * invoking the handler and checking the drive DMA status. We
617 * have an excessively incestuous relationship with the DMA
618 * logic that wants cleaning up.
619 */
620
621 void ide_timer_expiry (unsigned long data)
622 {
623 ide_hwif_t *hwif = (ide_hwif_t *)data;
624 ide_drive_t *uninitialized_var(drive);
625 ide_handler_t *handler;
626 unsigned long flags;
627 int wait = -1;
628 int plug_device = 0;
629 struct request *uninitialized_var(rq_in_flight);
630
631 spin_lock_irqsave(&hwif->lock, flags);
632
633 handler = hwif->handler;
634
635 if (handler == NULL || hwif->req_gen != hwif->req_gen_timer) {
636 /*
637 * Either a marginal timeout occurred
638 * (got the interrupt just as timer expired),
639 * or we were "sleeping" to give other devices a chance.
640 * Either way, we don't really want to complain about anything.
641 */
642 } else {
643 ide_expiry_t *expiry = hwif->expiry;
644 ide_startstop_t startstop = ide_stopped;
645
646 drive = hwif->cur_dev;
647
648 if (expiry) {
649 wait = expiry(drive);
650 if (wait > 0) { /* continue */
651 /* reset timer */
652 hwif->timer.expires = jiffies + wait;
653 hwif->req_gen_timer = hwif->req_gen;
654 add_timer(&hwif->timer);
655 spin_unlock_irqrestore(&hwif->lock, flags);
656 return;
657 }
658 }
659 hwif->handler = NULL;
660 hwif->expiry = NULL;
661 /*
662 * We need to simulate a real interrupt when invoking
663 * the handler() function, which means we need to
664 * globally mask the specific IRQ:
665 */
666 spin_unlock(&hwif->lock);
667 /* disable_irq_nosync ?? */
668 disable_irq(hwif->irq);
669 /* local CPU only, as if we were handling an interrupt */
670 local_irq_disable();
671 if (hwif->polling) {
672 startstop = handler(drive);
673 } else if (drive_is_ready(drive)) {
674 if (drive->waiting_for_dma)
675 hwif->dma_ops->dma_lost_irq(drive);
676 if (hwif->port_ops && hwif->port_ops->clear_irq)
677 hwif->port_ops->clear_irq(drive);
678
679 printk(KERN_WARNING "%s: lost interrupt/n",
680 drive->name);
681 startstop = handler(drive);
682 } else {
683 if (drive->waiting_for_dma)
684 startstop = ide_dma_timeout_retry(drive, wait);
685 else
686 startstop = ide_error(drive, "irq timeout",
687 hwif->tp_ops->read_status(hwif));
688 }
689 spin_lock_irq(&hwif->lock);
690 enable_irq(hwif->irq);
691 if (startstop == ide_stopped && hwif->polling == 0) {
692 rq_in_flight = hwif->rq;
693 hwif->rq = NULL;
694 ide_unlock_port(hwif);
695 plug_device = 1;
696 }
697 }
698 spin_unlock_irqrestore(&hwif->lock, flags);
699
700 if (plug_device) {
701 ide_unlock_host(hwif->host);
702 ide_requeue_and_plug(drive, rq_in_flight);
703 }
704 }
637-641行看到我说这几行,你可能有两个反应。第一是写错了,第二是有病。因为这时一段注释,说这段注释没有别的意思,就是因为第一眼看到他感觉这段话着实有点好笑。他大概的意思好像是说,“首先对于这个设备的超时我表示遗憾,我们也尽量去给这个设备新做人的机会,应为我们也不愿意看到他出现超时”。是不是颇有点老师的风范。
好了言归正传,648-658行我们确实看到了驱动给了设备新做人的机会。
659行前面也说过了,处理完中断这个hwif->handler 是要清空的,但是这里超时就是因为等待的中断没有到来,说以这里补上这个操作也是理所当然的了。
后面的代码也就比较简单了,既然超时了能补救的就补上,出了错的就报告错误的信息,一切都是本着对设备负责的态度。
苦海无边,该是回头的时候了。这样我们还是回到do_rw_taskfile中来,毕竟一切因果孽缘都始于她。说了这么久的handle还是来看一下task_no_data_intr,不然就对不起她了。
[ide-taskfile.c]
147 static ide_startstop_t task_no_data_intr(ide_drive_t *drive)
148 {
149 ide_hwif_t *hwif = drive->hwif;
150 struct ide_cmd *cmd = &hwif->cmd;
151 struct ide_taskfile *tf = &cmd->tf;
152 int custom = (cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) ? 1 : 0;
153 int retries = (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS) ? 5 : 1;
154 u8 stat;
155
156 local_irq_enable_in_hardirq();
157
158 while (1) {
159 stat = hwif->tp_ops->read_status(hwif);
160 if ((stat & ATA_BUSY) == 0 || retries-- == 0)
161 break;
162 udelay(10);
163 };
164
165 if (!OK_STAT(stat, ATA_DRDY, BAD_STAT)) {
166 if (custom && tf->command == ATA_CMD_SET_MULTI) {
167 drive->mult_req = drive->mult_count = 0;
168 drive->special_flags |= IDE_SFLAG_RECALIBRATE;
169 (void)ide_dump_status(drive, __func__, stat);
170 return ide_stopped;
171 } else if (custom && tf->command == ATA_CMD_INIT_DEV_PARAMS){
172 if ((stat & (ATA_ERR | ATA_DRQ)) == 0) {
173 ide_set_handler(drive, &task_no_data_intr,
174 WAIT_WORSTCASE);
175 return ide_started;
176 }
177 }
178 return ide_error(drive, "task_no_data_intr", stat);
179 }
180
181 if (custom && tf->command == ATA_CMD_SET_MULTI)
182 drive->mult_count = drive->mult_req;
183
184 if (custom == 0 || tf->command == ATA_CMD_IDLEIMMEDIATE ||
185 tf->command == ATA_CMD_CHK_POWER) {
186 struct request *rq = hwif->rq;
187
188 if (blk_pm_request(rq))
189 ide_complete_pm_rq(drive, rq);
190 else
191 ide_finish_cmd(drive, cmd, stat);
192 }
193
194 return ide_stopped;
195 }
我们知道对于nodata的命令等其实最终是完成一些状态的判断等工作,根据不同的命令返回状态的不同进行相应的处理,一旦出错就调用169、178等行的出错处理。最后,我们来看一下191行的处理。
[ide-taskfile.c]
324 void ide_finish_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat)
325 {
326 struct request *rq = drive->hwif->rq;
327 u8 err = ide_read_error(drive), nsect = cmd->tf.nsect;
328 u8 set_xfer = !!(cmd->tf_flags & IDE_TFLAG_SET_XFER);
329
330 ide_complete_cmd(drive, cmd, stat, err);
331 rq->errors = err;
332
333 if (err == 0 && set_xfer) {
334 ide_set_xfer_rate(drive, nsect);
335 ide_driveid_update(drive);
336 }
337
338 ide_complete_rq(drive, err ? -EIO : 0, blk_rq_bytes(rq));
339 }
这个函数包含了两个方面的内容一个就是结束设备本身的命令操作,另外就是结束块设备那边的request。分别对应代码的330和338行。
[ide-io.c]
74 void ide_complete_cmd(ide_drive_t *drive, struct ide_cmd *cmd, u8 stat, u8 err)
75 {
76 const struct ide_tp_ops *tp_ops = drive->hwif->tp_ops;
77 struct ide_taskfile *tf = &cmd->tf;
78 struct request *rq = cmd->rq;
79 u8 tf_cmd = tf->command;
80
81 tf->error = err;
82 tf->status = stat;
83
84 if (cmd->ftf_flags & IDE_FTFLAG_IN_DATA) {
85 u8 data[2];
86
87 tp_ops->input_data(drive, cmd, data, 2);
88
89 cmd->tf.data = data[0];
90 cmd->hob.data = data[1];
91 }
92
93 ide_tf_readback(drive, cmd);
94
95 if ((cmd->tf_flags & IDE_TFLAG_CUSTOM_HANDLER) &&
96 tf_cmd == ATA_CMD_IDLEIMMEDIATE) {
97 if (tf->lbal != 0xc4) {
98 printk(KERN_ERR "%s: head unload failed!/n",
99 drive->name);
100 ide_tf_dump(drive->name, cmd);
101 } else
102 drive->dev_flags |= IDE_DFLAG_PARKED;
103 }
104
105 if (rq && rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
106 struct ide_cmd *orig_cmd = rq->special;
107
108 if (cmd->tf_flags & IDE_TFLAG_DYN)
109 kfree(orig_cmd);
110 else
111 memcpy(orig_cmd, cmd, sizeof(*cmd));
112 }
113 }
这部分代码就不在详细说明了。
走来这么久整个ide驱动的构架也就基本上说完了,还是回到我们的这个故事的起点ide_disk_setup。
接下来的事情就比较简单了,从ide_disk_setup返回以后重新回到ide_gd_probe。接下来就到了402行,add_disk(g);这个函数是块设备那边的一个接口,会将这个重要的gendisk结构注册到块设备中,然后IDE设备也就开启了一个新的时代……