现在的位置: 首页 > 综合 > 正文

IDE硬盘驱动器读写过程

2018年05月19日 ⁄ 综合 ⁄ 共 6523字 ⁄ 字号 评论关闭

Linux内核在缺省配置下最多支持10IDE接口,IDE接口用ide_hwif_t结构来描述,每个IDE接口具有一对主-从驱动器接口,它们用ide_drive_t结构来描述,每个驱动器接口可接不同种类的IDE设备,IDE硬盘,光驱等,它们用ide_driver_t结构来描述
每个驱动器接口包含一个命令请求队列,request_queue_t结构来描述,具体的请求用request结构来描述
多个IDE驱动器可以共享一个中断,共享同一中断的驱动器形成一个组,ide_hwgroup_t结构来描述.ide_intr()是所有的ide驱动器所共用的硬件中断入口,对之对应的ide_hwgroup_t指针将作为dev_id传递给ide_intr. 
  每次在读写某个驱动器之前,需要用ide_set_handler()来设置ide_intr将要调用的中断函数指针.中断产生以后,该函数指针被自动清除
  do_rw_disk(drive,rq,block) 从逻辑扇区号block开始向IDE硬盘驱动器drive写入rq所描述的内容
  以下是硬盘PIO传输模式的有关代码
   
  ; drivers/ide/ide-disk.c 
  static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) 
  { 
  if (IDE_CONTROL_REG) 
  OUT_BYTE(drive->ctl,IDE_CONTROL_REG); 
  OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG); 
  if (drive->select.b.lba) { 如果是逻辑块寻址模式 
  OUT_BYTE(block,IDE_SECTOR_REG); 
  OUT_BYTE(block>>=8,IDE_LCYL_REG); 
  OUT_BYTE(block>>=8,IDE_HCYL_REG); 
  OUT_BYTE(((block>>&0x0f)|drive->select.all,IDE_SELECT_REG); 
  } else { 
  unsigned int sect,head,cyl,track; 
  track = block / drive->sect; 
  sect = block % drive->sect + 1; 
  OUT_BYTE(sect,IDE_SECTOR_REG); 
  head = track % drive->head; 
  cyl = track / drive->head; 
  OUT_BYTE(cyl,IDE_LCYL_REG); 
  OUT_BYTE(cyl>>8,IDE_HCYL_REG); 
  OUT_BYTE(head|drive->select.all,IDE_SELECT_REG); 
  } 
  if (rq->cmd == READ) {{ 
  ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); WAIT_CMD为10秒超时 
  OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG); 
  return ide_started; 
  } 
  if (rq->cmd == WRITE) { 
  ide_startstop_t startstop; 
  OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG); 
  if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { 
  printk(KERN_ERR "%s: no DRQ after issuing %s\n", drive->name, 
  drive->mult_count ? "MULTWRITE" : "WRITE"); 
  return startstop; 
  } 
  if (!drive->unmask) 
  __cli(); /* local CPU only */ 
  if (drive->mult_count) { 如果允许多扇区传送 
  ide_hwgroup_t *hwgroup = HWGROUP(drive); 
  /* 
  * Ugh.. this part looks ugly because we MUST set up 
  * the interrupt handler before outputting the first block 
  * of data to be written. If we hit an error (corrupted buffer list) 
  * in ide_multwrite(), then we need to remove the handler/timer 
  * before returning. Fortunately, this NEVER happens (right?). 
  * 
  * Except when you get an error it seems... 
  */ 
  hwgroup->wrq = *rq; /* scratchpad */ 
  ide_set_handler (drive, &multwrite_intr, WAIT_CMD, NULL); 
  if (ide_multwrite(drive, drive->mult_count)) { 
  unsigned long flags; 
  spin_lock_irqsave(&io_request_lock, flags); 
  hwgroup->handler = NULL; 
  del_timer(&hwgroup->timer); 
  spin_unlock_irqrestore(&io_request_lock, flags); 
  return ide_stopped; 
  } 
  } else { 
  ide_set_handler (drive, &write_intr, WAIT_CMD, NULL); 
  idedisk_output_data(drive, rq->buffer, SECTOR_WORDS); 写入一扇区SECTOR_WORDS=512/4 
  } 
  return ide_started; 
  } 
  printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd); 
  ide_end_request(0, HWGROUP(drive)); 
  return ide_stopped; 
  } 
  void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler, 
  unsigned int timeout, ide_expiry_t *expiry) 
  { 
  unsigned long flags; 
  ide_hwgroup_t *hwgroup = HWGROUP(drive); 
  spin_lock_irqsave(&io_request_lock, flags); 
  if (hwgroup->handler != NULL) { 
  printk("%s: ide_set_handler: handler not null; old=%p, new=%p\n", 
  drive->name, hwgroup->handler, handler); 
  } 
  hwgroup->handler = handler; 
  hwgroup->expiry = expiry; 
  hwgroup->timer.expires = jiffies + timeout; 
  add_timer(&hwgroup->timer); 
  spin_unlock_irqrestore(&io_request_lock, flags); 
  } 
  static inline void idedisk_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) 
  { 
  if (drive->bswap) { 
  idedisk_bswap_data(buffer, wcount); 
  ide_output_data(drive, buffer, wcount); 
  idedisk_bswap_data(buffer, wcount); 
  } else 
  ide_output_data(drive, buffer, wcount); 
  } 
  void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount) 
  { 
  byte io_32bit = drive->io_32bit; 
  if (io_32bit) { 
  #if SUPPORT_VLB_SYNC 
  if (io_32bit & 2) { 
  unsigned long flags; 
  __save_flags(flags); /* local CPU only */ 
  __cli(); /* local CPU only */ 
  do_vlb_sync(IDE_NSECTOR_REG); 
  outsl(IDE_DATA_REG, buffer, wcount); 
  __restore_flags(flags); /* local CPU only */ 
  } else 
  #endif /* SUPPORT_VLB_SYNC */ 
  outsl(IDE_DATA_REG, buffer, wcount); 
  } else { 
  #if SUPPORT_SLOW_DATA_PORTS 
  if (drive->slow) { 
  unsigned short *ptr = (unsigned short *) buffer; 
  while (wcount--) { 
  outw_p(*ptr++, IDE_DATA_REG); 
  outw_p(*ptr++, IDE_DATA_REG); 
  } 
  } else 
  #endif /* SUPPORT_SLOW_DATA_PORTS */ 
  outsw(IDE_DATA_REG, buffer, wcount<<1); 
  } 
  } 
  int ide_multwrite (ide_drive_t *drive, unsigned int mcount) 
  { 
  ide_hwgroup_t *hwgroup= HWGROUP(drive); 
  /* 
  * This may look a bit odd, but remember wrq is a copy of the 
  * request not the original. The pointers are real however so the 
  * bh's are not copies. Remember that or bad stuff will happen 
  * 
  * At the point we are called the drive has asked us for the 
  * data, and its our job to feed it, walking across bh boundaries 
  * if need be. 
  */ 
  struct request *rq = &hwgroup->wrq; 
  do { 
  unsigned long flags; 
  unsigned int nsect = rq->current_nr_sectors; 
  if (nsect > mcount) 
  nsect = mcount; 
  mcount -= nsect; 
  ; 这时mcount为剩余的必需传送的扇区数 
  idedisk_output_data(drive, rq->buffer, nsect<<7); 
  spin_lock_irqsave(&io_request_lock, flags); /* Is this really necessary? */ 
  #ifdef CONFIG_BLK_DEV_PDC4030 
  rq->sector += nsect; 
  #endif 
  if (((long)(rq->nr_sectors -= nsect)) <= 0) 
  spin_unlock_irqrestore(&io_request_lock, flags); 
  break; 
  } 
  if ((rq->current_nr_sectors -= nsect) == 0) { 
  if ((rq->bh = rq->bh->b_reqnext) != NULL) {{ 
  rq->current_nr_sectors = rq->bh->b_size>>9; 
  rq->buffer = rq->bh->b_data; 
  } else { 
  spin_unlock_irqrestore(&io_request_lock, flags); 
  printk("%s: buffer list corrupted (%ld, %ld, %d)\n", 
  drive->name, rq->current_nr_sectors, 
  rq->nr_sectors, nsect); 
  ide_end_request(0, hwgroup); 
  return 1; 
  } 
  } else { 
  /* Fix the pointer.. we ate data */ 
  rq->buffer += nsect << 9; 
  } 
  spin_unlock_irqrestore(&io_request_lock, flags); 
  } while (mcount); 
  return 0; 
  } 
  ; IDE接口共用中断入口 
  void ide_intr (int irq, void *dev_id, struct pt_regs *regs) 
  { 
  unsigned long flags; 
  ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id; 
  ide_hwif_t *hwif; 
  ide_drive_t *drive; 
  ide_handler_t *handler; 
  ide_startstop_t startstop; 
  spin_lock_irqsave(&io_request_lock, flags); 
  hwif = hwgroup->hwif; 
  if (!ide_ack_intr(hwif)) { 
  spin_unlock_irqrestore(&i

抱歉!评论已关闭.