X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fide%2Fide-taskfile.c;h=f7687df7cb6ebc3218573a7ced50421248e4a595;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=8de2a111b9f76655a1105b7bad09bf0d693bf67e;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 8de2a111b..f7687df7c 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -5,7 +5,7 @@ * Copyright (C) 2000-2002 Andre Hedrick * Copyright (C) 2001-2002 Klaus Smolin * IBM Storage Technology Division - * Copyright (C) 2003 Bartlomiej Zolnierkiewicz + * Copyright (C) 2003-2004 Bartlomiej Zolnierkiewicz * * The big the bad and the ugly. * @@ -44,12 +44,12 @@ #include #include #include +#include #include #include #include #include -#include #define DEBUG_TASKFILE 0 /* unset when fixed */ @@ -63,17 +63,14 @@ static void ata_bswap_data (void *buffer, int wcount) } } - -void taskfile_input_data (ide_drive_t *drive, void *buffer, u32 wcount) +static void taskfile_input_data(ide_drive_t *drive, void *buffer, u32 wcount) { HWIF(drive)->ata_input_data(drive, buffer, wcount); if (drive->bswap) ata_bswap_data(buffer, wcount); } -EXPORT_SYMBOL(taskfile_input_data); - -void taskfile_output_data (ide_drive_t *drive, void *buffer, u32 wcount) +static void taskfile_output_data(ide_drive_t *drive, void *buffer, u32 wcount) { if (drive->bswap) { ata_bswap_data(buffer, wcount); @@ -84,8 +81,6 @@ void taskfile_output_data (ide_drive_t *drive, void *buffer, u32 wcount) } } -EXPORT_SYMBOL(taskfile_output_data); - int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) { ide_task_t args; @@ -101,8 +96,6 @@ int taskfile_lib_get_identify (ide_drive_t *drive, u8 *buf) return ide_raw_taskfile(drive, &args, buf); } -EXPORT_SYMBOL(taskfile_lib_get_identify); - ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) { ide_hwif_t *hwif = HWIF(drive); @@ -150,15 +143,15 @@ ide_startstop_t do_rw_taskfile (ide_drive_t *drive, ide_task_t *task) case WIN_WRITEDMA_ONCE: case WIN_WRITEDMA: case WIN_WRITEDMA_EXT: - if (!hwif->ide_dma_write(drive)) - return ide_started; - break; case WIN_READDMA_ONCE: case WIN_READDMA: case WIN_READDMA_EXT: case WIN_IDENTIFY_DMA: - if (!hwif->ide_dma_read(drive)) + if (!hwif->dma_setup(drive)) { + hwif->dma_exec_cmd(drive, taskfile->command); + hwif->dma_start(drive); return ide_started; + } break; default: if (task->handler == NULL) @@ -206,7 +199,7 @@ ide_startstop_t set_geometry_intr (ide_drive_t *drive) return ide_stopped; if (stat & (ERR_STAT|DRQ_STAT)) - return DRIVER(drive)->error(drive, "set_geometry_intr", stat); + return ide_error(drive, "set_geometry_intr", stat); if (HWGROUP(drive)->handler != NULL) BUG(); @@ -225,7 +218,7 @@ ide_startstop_t recal_intr (ide_drive_t *drive) u8 stat; if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), READY_STAT, BAD_STAT)) - return DRIVER(drive)->error(drive, "recal_intr", stat); + return ide_error(drive, "recal_intr", stat); return ide_stopped; } @@ -242,7 +235,7 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive) local_irq_enable(); if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),READY_STAT,BAD_STAT)) { - return DRIVER(drive)->error(drive, "task_no_data_intr", stat); + return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */ } if (args) @@ -253,73 +246,6 @@ ide_startstop_t task_no_data_intr (ide_drive_t *drive) EXPORT_SYMBOL(task_no_data_intr); -static void task_buffer_sectors(ide_drive_t *drive, struct request *rq, - unsigned nsect, unsigned rw) -{ - char *buf = rq->buffer + blk_rq_offset(rq); - - rq->sector += nsect; - rq->current_nr_sectors -= nsect; - rq->nr_sectors -= nsect; - __task_sectors(drive, buf, nsect, rw); -} - -static inline void task_buffer_multi_sectors(ide_drive_t *drive, - struct request *rq, unsigned rw) -{ - unsigned int msect = drive->mult_count, nsect; - - nsect = rq->current_nr_sectors; - if (nsect > msect) - nsect = msect; - - task_buffer_sectors(drive, rq, nsect, rw); -} - -#ifdef CONFIG_IDE_TASKFILE_IO -static void task_sectors(ide_drive_t *drive, struct request *rq, - unsigned nsect, unsigned rw) -{ - if (rq->cbio) { /* fs request */ - rq->errors = 0; - task_bio_sectors(drive, rq, nsect, rw); - } else /* task request */ - task_buffer_sectors(drive, rq, nsect, rw); -} - -static inline void task_bio_multi_sectors(ide_drive_t *drive, - struct request *rq, unsigned rw) -{ - unsigned int nsect, msect = drive->mult_count; - - do { - nsect = rq->current_nr_sectors; - if (nsect > msect) - nsect = msect; - - task_bio_sectors(drive, rq, nsect, rw); - - if (!rq->nr_sectors) - msect = 0; - else - msect -= nsect; - } while (msect); -} - -static void task_multi_sectors(ide_drive_t *drive, - struct request *rq, unsigned rw) -{ - if (rq->cbio) { /* fs request */ - rq->errors = 0; - task_bio_multi_sectors(drive, rq, rw); - } else /* task request */ - task_buffer_multi_sectors(drive, rq, rw); -} -#else -# define task_sectors(d, rq, nsect, rw) task_buffer_sectors(d, rq, nsect, rw) -# define task_multi_sectors(d, rq, rw) task_buffer_multi_sectors(d, rq, rw) -#endif /* CONFIG_IDE_TASKFILE_IO */ - static u8 wait_drive_not_busy(ide_drive_t *drive) { ide_hwif_t *hwif = HWIF(drive); @@ -340,37 +266,92 @@ static u8 wait_drive_not_busy(ide_drive_t *drive) return stat; } +static void ide_pio_sector(ide_drive_t *drive, unsigned int write) +{ + ide_hwif_t *hwif = drive->hwif; + struct scatterlist *sg = hwif->sg_table; + struct page *page; +#ifdef CONFIG_HIGHMEM + unsigned long flags; +#endif + unsigned int offset; + u8 *buf; + + page = sg[hwif->cursg].page; + offset = sg[hwif->cursg].offset + hwif->cursg_ofs * SECTOR_SIZE; + + /* get the current page and offset */ + page = nth_page(page, (offset >> PAGE_SHIFT)); + offset %= PAGE_SIZE; + +#ifdef CONFIG_HIGHMEM + local_irq_save(flags); +#endif + buf = kmap_atomic(page, KM_BIO_SRC_IRQ) + offset; + + hwif->nleft--; + hwif->cursg_ofs++; + + if ((hwif->cursg_ofs * SECTOR_SIZE) == sg[hwif->cursg].length) { + hwif->cursg++; + hwif->cursg_ofs = 0; + } + + /* do the actual data transfer */ + if (write) + taskfile_output_data(drive, buf, SECTOR_WORDS); + else + taskfile_input_data(drive, buf, SECTOR_WORDS); + + kunmap_atomic(buf, KM_BIO_SRC_IRQ); +#ifdef CONFIG_HIGHMEM + local_irq_restore(flags); +#endif +} + +static void ide_pio_multi(ide_drive_t *drive, unsigned int write) +{ + unsigned int nsect; + + nsect = min_t(unsigned int, drive->hwif->nleft, drive->mult_count); + while (nsect--) + ide_pio_sector(drive, write); +} + static inline void ide_pio_datablock(ide_drive_t *drive, struct request *rq, unsigned int write) { + if (rq->bio) /* fs request */ + rq->errors = 0; + switch (drive->hwif->data_phase) { case TASKFILE_MULTI_IN: case TASKFILE_MULTI_OUT: - task_multi_sectors(drive, rq, write); + ide_pio_multi(drive, write); break; default: - task_sectors(drive, rq, 1, write); + ide_pio_sector(drive, write); break; } } -#ifdef CONFIG_IDE_TASKFILE_IO static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, const char *s, u8 stat) { if (rq->bio) { - int sectors = rq->hard_nr_sectors - rq->nr_sectors; + ide_hwif_t *hwif = drive->hwif; + int sectors = hwif->nsect - hwif->nleft; - switch (drive->hwif->data_phase) { + switch (hwif->data_phase) { case TASKFILE_IN: - if (rq->nr_sectors) + if (hwif->nleft) break; /* fall through */ case TASKFILE_OUT: sectors--; break; case TASKFILE_MULTI_IN: - if (rq->nr_sectors) + if (hwif->nleft) break; /* fall through */ case TASKFILE_MULTI_OUT: @@ -382,11 +363,8 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq, if (sectors > 0) drive->driver->end_request(drive, 1, sectors); } - return drive->driver->error(drive, s, stat); + return ide_error(drive, s, stat); } -#else -# define task_error(d, rq, s, stat) drive->driver->error(d, s, stat) -#endif static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) { @@ -407,9 +385,11 @@ static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat) */ ide_startstop_t task_in_intr (ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; struct request *rq = HWGROUP(drive)->rq; - u8 stat = HWIF(drive)->INB(IDE_STATUS_REG); + u8 stat = hwif->INB(IDE_STATUS_REG); + /* new way for dealing with premature shared PCI interrupts */ if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { if (stat & (ERR_STAT | DRQ_STAT)) return task_error(drive, rq, __FUNCTION__, stat); @@ -421,7 +401,7 @@ ide_startstop_t task_in_intr (ide_drive_t *drive) ide_pio_datablock(drive, rq, 0); /* If it was the last datablock check status and finish transfer. */ - if (!rq->nr_sectors) { + if (!hwif->nleft) { stat = wait_drive_not_busy(drive); if (!OK_STAT(stat, 0, BAD_R_STAT)) return task_error(drive, rq, __FUNCTION__, stat); @@ -439,20 +419,20 @@ EXPORT_SYMBOL(task_in_intr); /* * Handler for command with PIO data-out phase (Write/Write Multiple). */ -ide_startstop_t task_out_intr (ide_drive_t *drive) +static ide_startstop_t task_out_intr (ide_drive_t *drive) { + ide_hwif_t *hwif = drive->hwif; struct request *rq = HWGROUP(drive)->rq; - u8 stat; + u8 stat = hwif->INB(IDE_STATUS_REG); - stat = HWIF(drive)->INB(IDE_STATUS_REG); if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) return task_error(drive, rq, __FUNCTION__, stat); /* Deal with unexpected ATA data phase. */ - if (((stat & DRQ_STAT) == 0) ^ !rq->nr_sectors) + if (((stat & DRQ_STAT) == 0) ^ !hwif->nleft) return task_error(drive, rq, __FUNCTION__, stat); - if (!rq->nr_sectors) { + if (!hwif->nleft) { task_end_request(drive, rq, stat); return ide_stopped; } @@ -464,8 +444,6 @@ ide_startstop_t task_out_intr (ide_drive_t *drive) return ide_started; } -EXPORT_SYMBOL(task_out_intr); - ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) { ide_startstop_t startstop; @@ -489,7 +467,7 @@ ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) } EXPORT_SYMBOL(pre_task_out_intr); -int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf) +static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf) { struct request rq; @@ -517,14 +495,15 @@ int ide_diag_taskfile (ide_drive_t *drive, ide_task_t *args, unsigned long data_ rq.hard_nr_sectors = rq.nr_sectors; rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors; + + if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE) + rq.flags |= REQ_RW; } rq.special = args; return ide_do_drive_cmd(drive, &rq, ide_wait); } -EXPORT_SYMBOL(ide_diag_taskfile); - int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf) { return ide_diag_taskfile(drive, args, 0, buf); @@ -532,10 +511,6 @@ int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf) EXPORT_SYMBOL(ide_raw_taskfile); -#define MAX_DMA (256*SECTOR_WORDS) - -ide_startstop_t flagged_taskfile(ide_drive_t *, ide_task_t *); - int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) { ide_task_request_t *req_task; @@ -686,8 +661,6 @@ abort: return err; } -EXPORT_SYMBOL(ide_taskfile_ioctl); - int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf) { struct request rq; @@ -705,8 +678,6 @@ int ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, return ide_do_drive_cmd(drive, &rq, ide_wait); } -EXPORT_SYMBOL(ide_wait_cmd); - /* * FIXME : this needs to map into at taskfile. */ @@ -764,9 +735,7 @@ abort: return err; } -EXPORT_SYMBOL(ide_cmd_ioctl); - -int ide_wait_cmd_task (ide_drive_t *drive, u8 *buf) +static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf) { struct request rq; @@ -776,8 +745,6 @@ int ide_wait_cmd_task (ide_drive_t *drive, u8 *buf) return ide_do_drive_cmd(drive, &rq, ide_wait); } -EXPORT_SYMBOL(ide_wait_cmd_task); - /* * FIXME : this needs to map into at taskfile. */ @@ -796,8 +763,6 @@ int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg) return err; } -EXPORT_SYMBOL(ide_task_ioctl); - /* * NOTICE: This is additions from IBM to provide a discrete interface, * for selective taskregister access operations. Nice JOB Klaus!!! @@ -886,8 +851,8 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); /* - * (ks) In the flagged taskfile approch, we will used all specified - * registers and the register value will not be changed. Except the + * (ks) In the flagged taskfile approch, we will use all specified + * registers and the register value will not be changed, except the * select bit (master/slave) in the drive_head register. We must make * sure that the desired drive is selected. */ @@ -896,12 +861,11 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) case TASKFILE_OUT_DMAQ: case TASKFILE_OUT_DMA: - hwif->ide_dma_write(drive); - break; - case TASKFILE_IN_DMAQ: case TASKFILE_IN_DMA: - hwif->ide_dma_read(drive); + hwif->dma_setup(drive); + hwif->dma_exec_cmd(drive, taskfile->command); + hwif->dma_start(drive); break; default: @@ -919,5 +883,3 @@ ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task) return ide_started; } - -EXPORT_SYMBOL(flagged_taskfile);