?? pdc4030.c
字號:
if (!sectors_avail) goto read_again;read_next: rq = HWGROUP(drive)->rq; nsect = rq->current_nr_sectors; if (nsect > sectors_avail) nsect = sectors_avail; sectors_avail -= nsect;#ifdef CONFIG_IDE_TASKFILE_IO to = ide_map_buffer(rq, &flags); HWIF(drive)->ata_input_data(drive, to, nsect * SECTOR_WORDS);#else /* !CONFIG_IDE_TASKFILE_IO */ HWIF(drive)->ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);#endif /* CONFIG_IDE_TASKFILE_IO */#ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), " "buf=0x%08lx, rem=%ld\n", drive->name, rq->sector, rq->sector+nsect-1,#ifdef CONFIG_IDE_TASKFILE_IO (unsigned long) to,#else /* !CONFIG_IDE_TASKFILE_IO */ (unsigned long) rq->buffer,#endif /* CONFIG_IDE_TASKFILE_IO */ rq->nr_sectors-nsect);#endif /* DEBUG_READ */#ifdef CONFIG_IDE_TASKFILE_IO ide_unmap_buffer(to, &flags);#else /* !CONFIG_IDE_TASKFILE_IO */ rq->buffer += nsect<<9;#endif /* CONFIG_IDE_TASKFILE_IO */ rq->sector += nsect; rq->errors = 0; rq->nr_sectors -= nsect; total_remaining = rq->nr_sectors; if ((rq->current_nr_sectors -= nsect) <= 0) { DRIVER(drive)->end_request(drive, 1); }/* * Now the data has been read in, do the following: * * if there are still sectors left in the request, * if we know there are still sectors available from the interface, * go back and read the next bit of the request. * else if DRQ is asserted, there are more sectors available, so * go back and find out how many, then read them in. * else if BUSY is asserted, we are going to get an interrupt, so * set the handler for the interrupt and just return */ if (total_remaining > 0) { if (sectors_avail) goto read_next; status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (status.b.drq) goto read_again; if (status.b.bsy) { if (HWGROUP(drive)->handler != NULL) BUG(); ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL);#ifdef DEBUG_READ printk(KERN_DEBUG "%s: promise_read: waiting for" "interrupt\n", drive->name);#endif /* DEBUG_READ */ return ide_started; } printk(KERN_ERR "%s: Eeek! promise_read_intr: sectors left " "!DRQ !BUSY\n", drive->name); return DRIVER(drive)->error(drive, "promise read intr", status.all); } return ide_stopped;}/* * promise_complete_pollfunc() * This is the polling function for waiting (nicely!) until drive stops * being busy. It is invoked at the end of a write, after the previous poll * has finished. * * Once not busy, the end request is called. */static ide_startstop_t promise_complete_pollfunc(ide_drive_t *drive){ ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = hwgroup->rq; int i; if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { if (hwgroup->handler != NULL) BUG(); ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); return ide_started; /* continue polling... */ } hwgroup->poll_timeout = 0; printk(KERN_ERR "%s: completion timeout - still busy!\n", drive->name); return DRIVER(drive)->error(drive, "busy timeout", HWIF(drive)->INB(IDE_STATUS_REG)); } hwgroup->poll_timeout = 0;#ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name);#endif /* DEBUG_WRITE */ for (i = rq->nr_sectors; i > 0; ) { i -= rq->current_nr_sectors; DRIVER(drive)->end_request(drive, 1); } return ide_stopped;}/* * promise_multwrite() transfers a block of up to mcount sectors of data * to a drive as part of a disk multiple-sector write operation. * * Returns 0 on success. * * Note that we may be called from two contexts - the do_rw_disk context * and IRQ context. The IRQ can happen any time after we've output the * full "mcount" number of sectors, so we must make sure we update the * state _before_ we output the final part of the data! */int promise_multwrite (ide_drive_t *drive, unsigned int mcount){ ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = &hwgroup->wrq; do { char *buffer; int nsect = rq->current_nr_sectors;#ifdef CONFIG_IDE_TASKFILE_IO unsigned long flags;#endif /* CONFIG_IDE_TASKFILE_IO */ if (nsect > mcount) nsect = mcount; mcount -= nsect;#ifdef CONFIG_IDE_TASKFILE_IO buffer = ide_map_buffer(rq, &flags); rq->sector += nsect;#else /* !CONFIG_IDE_TASKFILE_IO */ buffer = rq->buffer; rq->sector += nsect; rq->buffer += nsect << 9;#endif /* CONFIG_IDE_TASKFILE_IO */ rq->nr_sectors -= nsect; rq->current_nr_sectors -= nsect; /* Do we move to the next bh after this? */ if (!rq->current_nr_sectors) { struct buffer_head *bh = rq->bh->b_reqnext; /* end early early we ran out of requests */ if (!bh) { mcount = 0; } else { rq->bh = bh; rq->current_nr_sectors = bh->b_size >> 9; rq->hard_cur_sectors = rq->current_nr_sectors; rq->buffer = bh->b_data; } } /* * Ok, we're all setup for the interrupt * re-entering us on the last transfer. */ taskfile_output_data(drive, buffer, nsect<<7);#ifdef CONFIG_IDE_TASKFILE_IO ide_unmap_buffer(buffer, &flags);#endif /* CONFIG_IDE_TASKFILE_IO */ } while (mcount); return 0;}/* * promise_write_pollfunc() is the handler for disk write completion polling. */static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive){ ide_hwgroup_t *hwgroup = HWGROUP(drive); if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { if (hwgroup->handler != NULL) BUG(); ide_set_handler(drive, &promise_write_pollfunc, HZ/100, NULL); return ide_started; /* continue polling... */ } hwgroup->poll_timeout = 0; printk(KERN_ERR "%s: write timed-out!\n",drive->name); return DRIVER(drive)->error(drive, "write timeout", HWIF(drive)->INB(IDE_STATUS_REG)); } /* * Now write out last 4 sectors and poll for not BUSY */ promise_multwrite(drive, 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; if (hwgroup->handler != NULL) BUG(); ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);#ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Done last 4 sectors - status = %02x\n", drive->name, HWIF(drive)->INB(IDE_STATUS_REG));#endif /* DEBUG_WRITE */ return ide_started;}/* * promise_write() transfers a block of one or more sectors of data to a * drive as part of a disk write operation. All but 4 sectors are transferred * in the first attempt, then the interface is polled (nicely!) for completion * before the final 4 sectors are transferred. There is no interrupt generated * on writes (at least on the DC4030VL-2), we just have to poll for NOT BUSY. */static ide_startstop_t promise_write (ide_drive_t *drive){ ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = &hwgroup->wrq;#ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), " "buffer=%p\n", drive->name, rq->sector, rq->sector + rq->nr_sectors - 1, rq->buffer);#endif /* DEBUG_WRITE */ /* * If there are more than 4 sectors to transfer, do n-4 then go into * the polling strategy as defined above. */ if (rq->nr_sectors > 4) { if (promise_multwrite(drive, rq->nr_sectors - 4)) return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; if (hwgroup->handler != NULL) /* paranoia check */ BUG(); ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); return ide_started; } else { /* * There are 4 or fewer sectors to transfer, do them all in one go * and wait for NOT BUSY. */ if (promise_multwrite(drive, rq->nr_sectors)) return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; if (hwgroup->handler != NULL) BUG(); ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL);#ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, " "status = %02x\n", drive->name, HWIF(drive)->INB(IDE_STATUS_REG));#endif /* DEBUG_WRITE */ return ide_started; }}/* * do_pdc4030_io() is called from promise_rw_disk, having had the block number * already set up. It issues a READ or WRITE command to the Promise * controller, assuming LBA has been used to set up the block number. */#ifndef CONFIG_IDE_TASKFILE_IOide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq){#else /* CONFIG_IDE_TASKFILE_IO */ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task){ struct request *rq = HWGROUP(drive)->rq; task_struct_t *taskfile = (task_struct_t *) task->tfRegister;#endif /* CONFIG_IDE_TASKFILE_IO */ ide_startstop_t startstop; unsigned long timeout; u8 stat = 0;#ifdef CONFIG_IDE_TASKFILE_IO if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ SELECT_MASK(drive, 0); HWIF(drive)->OUTB(taskfile->feature, IDE_FEATURE_REG); HWIF(drive)->OUTB(taskfile->sector_count, IDE_NSECTOR_REG); /* refers to number of sectors to transfer */ HWIF(drive)->OUTB(taskfile->sector_number, IDE_SECTOR_REG); /* refers to sector offset or start sector */ HWIF(drive)->OUTB(taskfile->low_cylinder, IDE_LCYL_REG); HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG); HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG);#endif /* CONFIG_IDE_TASKFILE_IO */ switch(rq->cmd) { case READ:#ifndef CONFIG_IDE_TASKFILE_IO HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG);#endif /* CONFIG_IDE_TASKFILE_IO *//* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be * generated by the card. If this is the case, we need to call the * "interrupt" handler (promise_read_intr) directly. Otherwise, if * an interrupt is going to occur, bit0 of the SELECT register will * be high, so we can set the handler the just return and be interrupted. * If neither of these is the case, we wait for up to 50ms (badly I'm * afraid!) until one of them is. */ timeout = jiffies + HZ/20; /* 50ms wait */ do { stat = HWIF(drive)->INB(IDE_STATUS_REG); if (stat & DRQ_STAT) { udelay(1); return promise_read_intr(drive); } if (HWIF(drive)->INB(IDE_SELECT_REG) & 0x01) {#ifdef DEBUG_READ printk(KERN_DEBUG "%s: read: waiting for " "interrupt\n", drive->name);#endif /* DEBUG_READ */ ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); return ide_started; } udelay(1); } while (time_before(jiffies, timeout)); printk(KERN_ERR "%s: reading: No DRQ and not " "waiting - Odd!\n", drive->name); return ide_stopped; case WRITE:#ifndef CONFIG_IDE_TASKFILE_IO HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG);#endif /* CONFIG_IDE_TASKFILE_IO */ if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing " "PROMISE_WRITE\n", drive->name); return startstop; } if (!drive->unmask) local_irq_disable(); HWGROUP(drive)->wrq = *rq; /* scratchpad */ return promise_write(drive); default: printk("KERN_WARNING %s: bad command: %d\n", drive->name, rq->cmd); DRIVER(drive)->end_request(drive, 0); return ide_stopped; }}static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block){ /* The four drives on the two logical (one physical) interfaces are distinguished by writing the drive number (0-3) to the Feature register. FIXME: Is promise_selectproc now redundant?? */ int drive_number = (HWIF(drive)->channel << 1) + drive->select.b.unit;#ifndef CONFIG_IDE_TASKFILE_IO ide_hwif_t *hwif = HWIF(drive); BUG_ON(rq->nr_sectors > 127); if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG);#ifdef DEBUG printk("%s: %sing: LBAsect=%ld, sectors=%ld, " "buffer=0x%08lx\n", drive->name, (rq->cmd==READ)?"read":"writ", block, rq->nr_sectors, (unsigned long) rq->buffer);#endif hwif->OUTB(drive_number, IDE_FEATURE_REG); hwif->OUTB(rq->nr_sectors, IDE_NSECTOR_REG); hwif->OUTB(block,IDE_SECTOR_REG); hwif->OUTB(block>>=8,IDE_LCYL_REG); hwif->OUTB(block>>=8,IDE_HCYL_REG); hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); return do_pdc4030_io(drive, rq);#else /* CONFIG_IDE_TASKFILE_IO */ struct hd_drive_task_hdr taskfile; ide_task_t args; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); taskfile.feature = drive_number; taskfile.sector_count = rq->nr_sectors; taskfile.sector_number = block; taskfile.low_cylinder = (block>>=8); taskfile.high_cylinder = (block>>=8); taskfile.device_head = ((block>>8)&0x0f)|drive->select.all; taskfile.command = (rq->cmd==READ)?PROMISE_READ:PROMISE_WRITE; memcpy(args.tfRegister, &taskfile, sizeof(struct hd_drive_task_hdr)); memset(args.hobRegister, 0, sizeof(struct hd_drive_hob_hdr)); /* We can't call ide_cmd_type_parser here, since it won't understand our command, but that doesn't matter, since we don't use the generic interrupt handlers either. Setup the bits of args that we do need. */ args.handler = NULL; args.rq = (struct request *) rq; rq->special = (ide_task_t *)&args; return do_pdc4030_io(drive, &args);#endif /* CONFIG_IDE_TASKFILE_IO */}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -