static void read_intr(void) { struct request *req; int i, retries = 100000; do { i = (unsigned) inb_p(HD_STATUS); if (i & BUSY_STAT) continue; if (!OK_STATUS(i)) break; if (i & DRQ_STAT) goto ok_to_read; } while (--retries > 0); dump_status("read_intr", i); bad_rw_intr(); hd_request(); return; ok_to_read: req = hd_req; insw(HD_DATA, req->buffer, 256); #ifdef DEBUG printk("%s: read: sector %ld, remaining = %u, buffer=%p\n", req->rq_disk->disk_name, blk_rq_pos(req) + 1, blk_rq_sectors(req) - 1, req->buffer+512); #endif if (hd_end_request(0, 512)) { SET_HANDLER(&read_intr); return; } (void) inb_p(HD_STATUS); #if (HD_DELAY > 0) last_req = read_timer(); #endif hd_request(); }
static void write_intr(void) { struct request *req = CURRENT; int i; int retries = 100000; do { i = (unsigned) inb_p(HD_STATUS); if (i & BUSY_STAT) continue; if (!OK_STATUS(i)) break; if ((req->nr_sectors <= 1) || (i & DRQ_STAT)) goto ok_to_write; } while (--retries > 0); dump_status("write_intr", i); bad_rw_intr(); hd_request(); return; ok_to_write: req->sector++; i = --req->nr_sectors; --req->current_nr_sectors; req->buffer += 512; if (!i || (req->bio && req->current_nr_sectors <= 0)) end_request(req, 1); if (i > 0) { SET_HANDLER(&write_intr); outsw(HD_DATA,req->buffer,256); local_irq_enable(); } else { #if (HD_DELAY > 0) last_req = read_timer(); #endif hd_request(); } return; }
static void reset_hd(void) { static int i; repeat: if (reset) { reset = 0; i = -1; reset_controller(); } else if (win_result()) { bad_rw_intr(); if (reset) goto repeat; } i++; if (i < NR_HD) { hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1, hd_info[i].cyl,WIN_SPECIFY,&reset_hd); if (reset) goto repeat; } else do_hd_request(); }
static void read_intr(void) { if (win_result()) { bad_rw_intr(); return; } if (this_request->nsector == 2) { this_request->nsector--; port_read(HD_DATA, this_request->bh->b_data, 256); } else { port_read(HD_DATA, this_request->bh->b_data + 512, 256); return; } this_request->errors = 0; this_request->bh->b_uptodate = 1; this_request->bh->b_dirt = 0; wake_up(&wait_for_request); unlock_buffer(this_request->bh); this_request->hd = -1; this_request = this_request->next; do_request(); }
static void read_intr(void) { /* check previous read command success or not */ if (win_result()) { bad_rw_intr(); do_hd_request(); return; } /* read data from hard disk from data register */ port_read(HD_DATA, CURRENT_REQ->buffer, 256); CURRENT_REQ->errors = 0; CURRENT_REQ->buffer += 512; CURRENT_REQ->start_sector++; if (--CURRENT_REQ->nr_sectors) { do_hd = &read_intr; return; } end_request(1); do_hd_request(); }
/* * The driver enables interrupts as much as possible. In order to do this, * (a) the device-interrupt is disabled before entering hd_request(), * and (b) the timeout-interrupt is disabled before the sti(). * * Interrupts are still masked (by default) whenever we are exchanging * data/cmds with a drive, because some drives seem to have very poor * tolerance for latency during I/O. The IDE driver has support to unmask * interrupts for non-broken hardware, so use that driver if required. */ static void hd_request(void) { unsigned int block, nsect, sec, track, head, cyl; struct hd_i_struct *disk; struct request *req; if (do_hd) return; repeat: del_timer(&device_timer); local_irq_enable(); req = CURRENT; if (!req) { do_hd = NULL; return; } if (reset) { local_irq_disable(); reset_hd(); return; } disk = req->rq_disk->private_data; block = req->sector; nsect = req->nr_sectors; if (block >= get_capacity(req->rq_disk) || ((block+nsect) > get_capacity(req->rq_disk))) { printk("%s: bad access: block=%d, count=%d\n", req->rq_disk->disk_name, block, nsect); end_request(req, 0); goto repeat; } if (disk->special_op) { if (do_special_op(disk, req)) goto repeat; return; } sec = block % disk->sect + 1; track = block / disk->sect; head = track % disk->head; cyl = track / disk->head; #ifdef DEBUG printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ", cyl, head, sec, nsect, req->buffer); #endif if (blk_fs_request(req)) { switch (rq_data_dir(req)) { case READ: hd_out(disk,nsect,sec,head,cyl,WIN_READ,&read_intr); if (reset) goto repeat; break; case WRITE: hd_out(disk,nsect,sec,head,cyl,WIN_WRITE,&write_intr); if (reset) goto repeat; if (wait_DRQ()) { bad_rw_intr(); goto repeat; } outsw(HD_DATA,req->buffer,256); break; default: printk("unknown hd-command\n"); end_request(req, 0); break; } } }
void do_hd_request(void) { int i, r = 0; unsigned int start_sector, dev, partition; unsigned int start_sec, head, cyl; unsigned int nsect; CHECK_REQUEST; partition = MINOR(CURRENT_REQ->dev); /* get partition */ start_sector = CURRENT_REQ->start_sector; nsect = CURRENT_REQ->nr_sectors; /* need to check if nsect is exceed the partition limit or not */ if (partition >= 5 * NR_HD || nsect > hd[partition].nr_sects) { end_request(0); goto repeat; /* repeat defined in blk.h */ } start_sector += hd[partition].start_sect; dev = partition / 5; /* get cyl, head, start_sec number according start_sector */ /* div result: EAX = Quotient, EDX = Remainder */ /* * start_sector / sect nrs per track = total track number(start_sector) * ... remainder sector number(start_sec) */ __asm__("divl %4" :"=a" (start_sector), "=d" (start_sec) :"0" (start_sector), "1" (0), "r" (hd_info[dev].sect)); /* totoal track number / total head nrs = cylinder number(cyl) * ... head nr(head) */ __asm__("divl %4" :"=a" (cyl), "=d" (head) :"0" (start_sector), "1" (0), "r" (hd_info[dev].head)); start_sec++; if (reset) { reset = 0; recalibrate = 1; reset_hd(CURRENT_DEV); return; } if (recalibrate) { recalibrate = 0; hd_out(dev, hd_info[CURRENT_DEV].sect, 0, 0, 0, WIN_RESTORE, recal_intr); return; } if (CURRENT_REQ->cmd == WRITE) { hd_out(dev, nsect, start_sec, head, cyl, WIN_WRITE, write_intr); /* wait DRQ_STAT signal */ for(i = 0; i < 3000 && !(r = inb_p(HD_STATUS) & DRQ_STAT); i++) /* nothing */ ; if (!r) { bad_rw_intr(); goto repeat; } /* write 512 byte (1 sector) to HD */ port_write(HD_DATA, CURRENT_REQ->buffer, 256); } else if (CURRENT_REQ->cmd == READ) { hd_out(dev, nsect, start_sec, head, cyl, WIN_READ, read_intr); } else { panic("unknown hd-command"); } }
static void recal_intr(void) { if (win_result()) bad_rw_intr(); do_hd_request(); }
void do_hd_request(void) { int i,r = 0; unsigned int block,dev; unsigned int sec,head,cyl; unsigned int nsect; INIT_REQUEST; dev = MINOR(CURRENT->dev); //printk("In hd.c do_hd_request() dev (1st) is %d\n",dev ); block = CURRENT->sector; if (dev >= 5*NR_HD || block+2 > hd[dev].nr_sects) { end_request(0); goto repeat; } block += hd[dev].start_sect; dev /= 5; //printk("IN hd.c do_hd_quest() dev (2st) is %d\n",dev); __asm__("divl %4":"=a" (block),"=d" (sec):"0" (block),"1" (0), "r" (hd_info[dev].sect)); __asm__("divl %4":"=a" (cyl),"=d" (head):"0" (block),"1" (0), "r" (hd_info[dev].head)); sec++; nsect = CURRENT->nr_sectors; if (reset) { reset = 0; recalibrate = 1; reset_hd(CURRENT_DEV); return; } if (recalibrate) { recalibrate = 0; hd_out(dev,hd_info[CURRENT_DEV].sect,0,0,0, WIN_RESTORE,&recal_intr); return; } if (CURRENT->cmd == WRITE) { //printk("In hd.c do_hd_request() dev (1st) is %d\n",dev ); //hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); if(work == 1) { devi = 0; hd_out(devi,nsect,sec,head,cyl,WIN_WRITE,&write_intr); }else if(work == 2) { devi = 1; hd_out(devi,nsect,sec,head,cyl,WIN_WRITE,&write_intr); }else if (work == 3) { hd_out(devi,nsect,sec,head,cyl,WIN_WRITE,&write_intr); } //printk("devi is %d" ,devi); for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) /* nothing */ ; //hd_out(1,nsect,sec,head,cyl,WIN_WRITE,&write_intr); //for(i=0 ; i<3000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++) /* nothing */ ; if (!r) { bad_rw_intr(); goto repeat; } port_write(HD_DATA,CURRENT->buffer,256); } else if (CURRENT->cmd == READ) { if(work == 1) { dev = 0 ; } else if (work == 2) { dev = 1; } hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); } else panic("unknown hd-command"); }
/* * The driver enables interrupts as much as possible. In order to do this, * (a) the device-interrupt is disabled before entering hd_request(), * and (b) the timeout-interrupt is disabled before the sti(). * * Interrupts are still masked (by default) whenever we are exchanging * data/cmds with a drive, because some drives seem to have very poor * tolerance for latency during I/O. The IDE driver has support to unmask * interrupts for non-broken hardware, so use that driver if required. */ static void hd_request(void) { unsigned int block, nsect, sec, track, head, cyl; struct hd_i_struct *disk; struct request *req; if (do_hd) return; repeat: del_timer(&device_timer); if (!hd_req) { hd_req = blk_fetch_request(hd_queue); if (!hd_req) { do_hd = NULL; return; } } req = hd_req; if (reset) { reset_hd(); return; } disk = req->rq_disk->private_data; block = blk_rq_pos(req); nsect = blk_rq_sectors(req); if (block >= get_capacity(req->rq_disk) || ((block+nsect) > get_capacity(req->rq_disk))) { printk("%s: bad access: block=%d, count=%d\n", req->rq_disk->disk_name, block, nsect); hd_end_request_cur(-EIO); goto repeat; } if (disk->special_op) { if (do_special_op(disk, req)) goto repeat; return; } sec = block % disk->sect + 1; track = block / disk->sect; head = track % disk->head; cyl = track / disk->head; #ifdef DEBUG printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", req->rq_disk->disk_name, req_data_dir(req) == READ ? "read" : "writ", cyl, head, sec, nsect, req->buffer); #endif if (req->cmd_type == REQ_TYPE_FS) { switch (rq_data_dir(req)) { case READ: hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ, &read_intr); if (reset) goto repeat; break; case WRITE: hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE, &write_intr); if (reset) goto repeat; if (wait_DRQ()) { bad_rw_intr(); goto repeat; } outsw(HD_DATA, req->buffer, 256); break; default: printk("unknown hd-command\n"); hd_end_request_cur(-EIO); break; } } }