龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 操作系统 > LINUX系统 >

分析IDE硬盘驱动器读写过程

时间:2011-03-20 22:37来源:未知 作者:admin 点击:
分享到:
作者:opera Linux内核在缺省配置下最多支持10个IDE接口,IDE接口用ide_hwif_t结构来描述,每个IDE接口具有一对主-从驱动器接口,它们用ide_drive_t结构来描述,每个驱动器接口可接不同种类的IDE设

  作者:opera

  Linux内核在缺省配置下最多支持10个IDE接口,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

  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

  #endif

  if (((long)(rq->nr_sectors -= nsect)) 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

  if (!ide_ack_intr(hwif)) {

  spin_unlock_irqrestore(&i

精彩图集

赞助商链接