diff -urN linux-2.5.7/drivers/ide/hpt34x.c linux-2.5.7.fix/drivers/ide/hpt34x.c --- linux-2.5.7/drivers/ide/hpt34x.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/hpt34x.c Fri Mar 22 21:47:09 2002 @@ -334,6 +334,8 @@ drive->waiting_for_dma = 1; if (drive->type != ATA_DISK) return 0; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); /* issue cmd to drive */ OUT_BYTE((reading == 9) ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); return 0; diff -urN linux-2.5.7/drivers/ide/icside.c linux-2.5.7.fix/drivers/ide/icside.c --- linux-2.5.7/drivers/ide/icside.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/icside.c Fri Mar 22 21:47:41 2002 @@ -444,6 +444,9 @@ if (drive->media != ide_disk) return 0; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + ide_set_handler(drive, &icside_dmaintr, WAIT_CMD, NULL); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); diff -urN linux-2.5.7/drivers/ide/ide-cd.c linux-2.5.7.fix/drivers/ide/ide-cd.c --- linux-2.5.7/drivers/ide/ide-cd.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/ide-cd.c Fri Mar 22 21:50:58 2002 @@ -745,6 +745,9 @@ (void) (HWIF(drive)->dmaproc(ide_dma_begin, drive)); if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt) { + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, handler, WAIT_CMD, cdrom_timer_expiry); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */ return ide_started; @@ -786,6 +789,9 @@ return startstop; } + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + /* Arm the interrupt handler. */ ide_set_handler (drive, handler, timeout, cdrom_timer_expiry); @@ -1005,6 +1011,9 @@ /* Done moving data! Wait for another interrupt. */ + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &cdrom_read_intr, WAIT_CMD, NULL); return ide_started; } @@ -1335,6 +1344,9 @@ } /* Now we wait for another interrupt. */ + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &cdrom_pc_intr, WAIT_CMD, cdrom_timer_expiry); return ide_started; } @@ -1559,6 +1571,9 @@ } /* re-arm handler */ + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &cdrom_write_intr, 5 * WAIT_CMD, NULL); return ide_started; } diff -urN linux-2.5.7/drivers/ide/ide-dma.c linux-2.5.7.fix/drivers/ide/ide-dma.c --- linux-2.5.7/drivers/ide/ide-dma.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/ide-dma.c Fri Mar 22 21:51:28 2002 @@ -588,6 +588,9 @@ drive->waiting_for_dma = 1; if (drive->type != ATA_DISK) return 0; + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, dma_timer_expiry); /* issue cmd to drive */ if ((HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE) && (drive->addressing == 1)) { diff -urN linux-2.5.7/drivers/ide/ide-floppy.c linux-2.5.7.fix/drivers/ide/ide-floppy.c --- linux-2.5.7/drivers/ide/ide-floppy.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/ide-floppy.c Fri Mar 22 21:54:53 2002 @@ -968,6 +968,9 @@ if (temp > pc->buffer_size) { printk (KERN_ERR "ide-floppy: The floppy wants to send us more data than expected - discarding data\n"); idefloppy_discard_data (drive,bcount.all); + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); return ide_started; } @@ -990,6 +993,8 @@ pc->actually_transferred+=bcount.all; /* Update the current position */ pc->current_position+=bcount.all; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive,&idefloppy_pc_intr,IDEFLOPPY_WAIT_CMD, NULL); /* And set the interrupt handler again */ return ide_started; } @@ -1014,6 +1019,8 @@ printk (KERN_ERR "ide-floppy: (IO,CoD) != (0,1) while issuing a packet command\n"); return ide_stopped; } + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &idefloppy_pc_intr, IDEFLOPPY_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive, floppy->pc->c, 12); /* Send the actual packet */ return ide_started; @@ -1062,9 +1069,13 @@ * 25msec is too short, 40 and 50msec work well. idefloppy_pc_intr will * not be actually used until after the packet is moved in about 50 msec. */ + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + ide_set_handler (drive, &idefloppy_pc_intr, /* service routine for packet command */ - floppy->ticks, /* wait this long before "failing" */ + floppy->ticks, /* wait this long before "failing" */ &idefloppy_transfer_pc2); /* fail == transfer_pc2 */ return ide_started; } @@ -1145,6 +1156,9 @@ } if (test_bit (IDEFLOPPY_DRQ_INTERRUPT, &floppy->flags)) { + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, pkt_xfer_routine, IDEFLOPPY_WAIT_CMD, NULL); OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* Issue the packet command */ return ide_started; diff -urN linux-2.5.7/drivers/ide/ide-pmac.c linux-2.5.7.fix/drivers/ide/ide-pmac.c --- linux-2.5.7/drivers/ide/ide-pmac.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/ide-pmac.c Fri Mar 22 21:55:20 2002 @@ -993,6 +993,8 @@ drive->waiting_for_dma = 1; if (drive->media != ide_disk) return 0; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(func==ide_dma_write? WIN_WRITEDMA: WIN_READDMA, IDE_COMMAND_REG); diff -urN linux-2.5.7/drivers/ide/ide-tape.c linux-2.5.7.fix/drivers/ide/ide-tape.c --- linux-2.5.7/drivers/ide/ide-tape.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/ide-tape.c Fri Mar 22 21:57:56 2002 @@ -2155,6 +2155,9 @@ if (temp > pc->buffer_size) { printk (KERN_ERR "ide-tape: The tape wants to send us more data than expected - discarding data\n"); idetape_discard_data (drive, bcount.all); + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); return ide_started; } @@ -2181,6 +2184,9 @@ if (tape->debug_level >= 2) printk(KERN_INFO "ide-tape: [cmd %x] transferred %d bytes on that interrupt\n", pc->c[0], bcount.all); #endif + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* And set the interrupt handler again */ return ide_started; } @@ -2255,6 +2261,8 @@ return ide_stopped; } tape->cmd_start_time = jiffies; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &idetape_pc_intr, IDETAPE_WAIT_CMD, NULL); /* Set the interrupt routine */ atapi_output_bytes (drive,pc->c,12); /* Send the actual packet */ return ide_started; @@ -2328,6 +2336,9 @@ } #endif /* CONFIG_BLK_DEV_IDEDMA */ if (test_bit(IDETAPE_DRQ_INTERRUPT, &tape->flags)) { + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &idetape_transfer_pc, IDETAPE_WAIT_CMD, NULL); OUT_BYTE(WIN_PACKETCMD, IDE_COMMAND_REG); return ide_started; diff -urN linux-2.5.7/drivers/ide/ide-taskfile.c linux-2.5.7.fix/drivers/ide/ide-taskfile.c --- linux-2.5.7/drivers/ide/ide-taskfile.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/ide-taskfile.c Sat Mar 23 02:48:14 2002 @@ -1,8 +1,27 @@ /* - * Copyright (C) 2000 Michael Cornwell - * Copyright (C) 2000 Andre Hedrick + * linux/drivers/ide/ide-taskfile.c Version 0.30 Mar 23, 2002 * - * May be copied or modified under the terms of the GNU General Public License + * Copyright (C) 2000-2002 Michael Cornwell + * Copyright (C) 2000-2002 Andre Hedrick + * + * The big the bad and the ugly. + * + * Problems to be fixed because of BIO interface or the lack therefore. + * + * Fill me in stupid !!! + * + * HOST: + * General refers to the Controller and Driver "pair". + * DATA HANDLER: + * Under the context of Linux it generally refers to an interrupt handler. + * However, it correctly describes the 'HOST' + * DATA BLOCK: + * The amount of data needed to be transfered as predefined in the + * setup of the device. + * STORAGE ATOMIC: + * The 'DATA BLOCK' associated to the 'DATA HANDLER', and can be as + * small as a single sector or as large as the entire command block + * request. */ #include @@ -33,7 +52,7 @@ #define DEBUG_TASKFILE 0 /* unset when fixed */ #if DEBUG_TASKFILE -#define DTF(x...) printk(##x) +#define DTF(x...) printk(x) #else #define DTF(x...) #endif @@ -55,7 +74,7 @@ unsigned long *flags) { if (rq->bio) - bio_kunmap_irq(to, flags); + bio_kunmap_irq(to, flags); } static void bswap_data (void *buffer, int wcount) @@ -288,42 +307,52 @@ break; } } -static ide_startstop_t bio_mulout_intr(ide_drive_t *drive); /* + * FIXME before 2.6 ... DATA integrity issue upon error. + */ +/* * Handler for command write multiple * Called directly from execute_drive_cmd for the first bunch of sectors, * afterwards only by the ISR */ static ide_startstop_t task_mulout_intr(ide_drive_t *drive) { - unsigned int msect, nsect; - byte stat = GET_STAT(); - byte io_32bit = drive->io_32bit; - struct request *rq = HWGROUP(drive)->rq; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - char *pBuf = NULL; + byte stat = GET_STAT(); + byte io_32bit = drive->io_32bit; + struct request *rq = HWGROUP(drive)->rq; + ide_hwgroup_t *hwgroup = HWGROUP(drive); + char *pBuf = NULL; + ide_startstop_t startstop = ide_stopped; + unsigned int msect = drive->mult_count; + unsigned int nsect; unsigned long flags; +/* + * held here as a referrence to the past. + * __ide_end_request(drive, 1, rq->hard_nr_sectors); + */ /* * (ks/hs): Handle last IRQ on multi-sector transfer, * occurs after all data was sent in this chunk */ if (rq->current_nr_sectors == 0) { - if (stat & (ERR_STAT|DRQ_STAT)) + if (stat & (ERR_STAT|DRQ_STAT)) { + printk("%s: MULTI-WRITE assume all data transfered " \ + "is bad status=0x%02x\n", + drive->name, stat); return ide_error(drive, "task_mulout_intr", stat); - - /* - * there may be more, ide_do_request will restart it if - * necessary - */ - ide_end_request(drive, 1); - - return ide_stopped; + } + if (!rq->bio) + ide_end_request(drive, 1); + return startstop; } if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { + printk("%s: MULTI-WRITE assume all data transfered " \ + "is bad status=0x%02x\n", + drive->name, stat); return ide_error(drive, "task_mulout_intr", stat); } /* no data yet, so wait for another interrupt */ @@ -332,22 +361,41 @@ return ide_started; } - /* (ks/hs): See task_mulin_intr */ - msect = drive->mult_count; - nsect = rq->current_nr_sectors; - if (nsect > msect) - nsect = msect; + if (HWGROUP(drive)->handler != NULL) { + unsigned long lflags; + spin_lock_irqsave(&ide_lock, lflags); + HWGROUP(drive)->handler = NULL; + del_timer(&HWGROUP(drive)->timer); + spin_unlock_irqrestore(&ide_lock, lflags); + } - pBuf = ide_map_rq(rq, &flags); - DTF("Multiwrite: %p, nsect: %d , rq->current_nr_sectors: %ld\n", - pBuf, nsect, rq->current_nr_sectors); - drive->io_32bit = 0; - taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); - ide_unmap_rq(rq, pBuf, &flags); - drive->io_32bit = io_32bit; + do { + nsect = rq->current_nr_sectors; + if (nsect > msect) + nsect = msect; + pBuf = ide_map_rq(rq, &flags); + DTF("Multiwrite: %p, nsect: %d, msect: %d, " \ + "rq->current_nr_sectors: %ld\n", + pBuf, nsect, msect, rq->current_nr_sectors); + msect -= nsect; + drive->io_32bit = 0; + taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); + ide_unmap_rq(rq, pBuf, &flags); + rq->current_nr_sectors -= nsect; + drive->io_32bit = io_32bit; + /* + * FIXME :: We really can not legally get a new page/bio + * regardless, if this is the end of our segment. + * BIO walking or segment can only be updated after we + * have a good GET_STAT(); return. + */ + if (!rq->current_nr_sectors) { + if (!ide_end_request(drive, 1)) + if (!rq->bio) + return ide_stopped; + } + } while (msect); rq->errors = 0; - /* Are we sure that this as all been already transfered? */ - rq->current_nr_sectors -= nsect; if (hwgroup->handler == NULL) ide_set_handler(drive, &task_mulout_intr, WAIT_CMD, NULL); return ide_started; @@ -361,11 +409,10 @@ byte HIHI = (drive->addressing) ? 0xE0 : 0xEF; /* (ks/hs): Moved to start, do not use for multiple out commands */ - if (task->handler != task_mulout_intr && task->handler != bio_mulout_intr) { - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(HWIF(drive), drive, 0); - } + /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive), drive, 0); if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) && @@ -389,11 +436,6 @@ if (task->handler != NULL) { ide_set_handler (drive, task->handler, WAIT_CMD, NULL); OUT_BYTE(taskfile->command, IDE_COMMAND_REG); - /* - * Warning check for race between handler and prehandler for - * writing first block of data. however since we are well - * inside the boundaries of the seek, we should be okay. - */ if (task->prehandler != NULL) { return task->prehandler(drive, task->rq); } @@ -405,7 +447,12 @@ return ide_started; } -void do_taskfile(ide_drive_t *drive, struct hd_drive_task_hdr *taskfile, +/* + * FIXME :: Need to merge all taskfile requests regardless of caller + * to the above do_rw_taskfile. + */ +void do_taskfile(ide_drive_t *drive, + struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile, ide_handler_t *handler) { @@ -413,11 +460,10 @@ byte HIHI = (drive->addressing) ? 0xE0 : 0xEF; /* (ks/hs): Moved to start, do not use for multiple out commands */ - if (*handler != task_mulout_intr && handler != bio_mulout_intr) { - if (IDE_CONTROL_REG) - OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ - SELECT_MASK(HWIF(drive), drive, 0); - } + /* ALL Command Block Executions SHALL clear nIEN, unless otherwise */ + if (IDE_CONTROL_REG) + OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ + SELECT_MASK(HWIF(drive), drive, 0); if ((id->command_set_2 & 0x0400) && (id->cfs_enable_2 & 0x0400) && @@ -477,6 +523,8 @@ if (stat & (ERR_STAT|DRQ_STAT)) return ide_error(drive, "set_geometry_intr", stat); + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &set_geometry_intr, WAIT_CMD, NULL); return ide_started; } @@ -513,7 +561,10 @@ } /* - * Handler for command with PIO data-in phase + * Handler for command with PIO data-in phase, READ + */ +/* + * FIXME before 2.6 ... DATA integrity issue upon error. */ static ide_startstop_t task_in_intr (ide_drive_t *drive) { @@ -525,65 +576,80 @@ if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { +#if 0 + DTF("%s: READ attempting to recover last " \ + "sector counter status=0x%02x\n", + drive->name, stat); + /* + * Expect a BUG BOMB if we attempt to rewind the + * offset in the BIO aka PAGE in the current BLOCK + * segment. This is different than the HOST segment. + */ + + rq->current_nr_sectors++; +#endif return ide_error(drive, "task_in_intr", stat); } if (!(stat & BUSY_STAT)) { DTF("task_in_intr to Soon wait for next interrupt\n"); - ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); + if (HWGROUP(drive)->handler == NULL) + ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); return ide_started; } } - DTF("stat: %02x\n", stat); pBuf = ide_map_rq(rq, &flags); - DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); - + DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n", + pBuf, (int) rq->current_nr_sectors, stat); drive->io_32bit = 0; taskfile_input_data(drive, pBuf, SECTOR_WORDS); ide_unmap_rq(rq, pBuf, &flags); drive->io_32bit = io_32bit; - - if (--rq->current_nr_sectors <= 0) { - /* (hs): swapped next 2 lines */ - DTF("Request Ended stat: %02x\n", GET_STAT()); - if (ide_end_request(drive, 1)) { - ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); - return ide_started; - } - } else { + /* + * FIXME :: We really can not legally get a new page/bio + * regardless, if this is the end of our segment. + * BIO walking or segment can only be updated after we have a good + * GET_STAT(); return. + */ + if (--rq->current_nr_sectors <= 0) + if (!ide_end_request(drive, 1)) + return ide_stopped; + if (HWGROUP(drive)->handler == NULL) ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL); - return ide_started; - } - return ide_stopped; + return ide_started; } +/* + * VERIFY ME before 2.6 ... unexpected race is possible based on details + * RMK with 74LS245/373/374 TTL buffer logic because of passthrough. + */ static ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) { - ide_task_t *args = rq->special; + char *pBuf = NULL; + unsigned long flags; ide_startstop_t startstop; - 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"); + 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->addressing ? "WRITE_EXT" : "WRITE"); return startstop; } - - /* (ks/hs): Fixed Multi Write */ - if ((args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE) && - (args->tfRegister[IDE_COMMAND_OFFSET] != WIN_MULTWRITE_EXT)) { - unsigned long flags; - char *buf = ide_map_rq(rq, &flags); - /* For Write_sectors we need to stuff the first sector */ - taskfile_output_data(drive, buf, SECTOR_WORDS); - rq->current_nr_sectors--; - ide_unmap_rq(rq, buf, &flags); - } else { - ata_poll_drive_ready(drive); - return args->handler(drive); - } + /* For Write_sectors we need to stuff the first sector */ + pBuf = ide_map_rq(rq, &flags); + taskfile_output_data(drive, pBuf, SECTOR_WORDS); + /* + * WARNING :: Interrupt could happen instantly :-/ + */ + rq->current_nr_sectors--; + ide_unmap_rq(rq, pBuf, &flags); return ide_started; } /* - * Handler for command with PIO data-out phase + * Handler for command with PIO data-out phase WRITE + * + * WOOHOO this is a CORRECT STATE DIAGRAM NOW, */ static ide_startstop_t task_out_intr(ide_drive_t *drive) { @@ -593,17 +659,25 @@ char *pBuf = NULL; unsigned long flags; - if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) + if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) { + DTF("%s: WRITE attempting to recover last " \ + "sector counter status=0x%02x\n", + drive->name, stat); + rq->current_nr_sectors++; return ide_error(drive, "task_out_intr", stat); - + } + /* + * Safe to update request for partial completions. + * We have a good STATUS CHECK!!! + */ if (!rq->current_nr_sectors) if (!ide_end_request(drive, 1)) return ide_stopped; - if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { rq = HWGROUP(drive)->rq; pBuf = ide_map_rq(rq, &flags); - DTF("write: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors); + DTF("write: %p, rq->current_nr_sectors: %d\n", + pBuf, (int) rq->current_nr_sectors); drive->io_32bit = 0; taskfile_output_data(drive, pBuf, SECTOR_WORDS); ide_unmap_rq(rq, pBuf, &flags); @@ -611,145 +685,73 @@ rq->errors = 0; rq->current_nr_sectors--; } - - ide_set_handler(drive, task_out_intr, WAIT_CMD, NULL); + if (HWGROUP(drive)->handler == NULL) + ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL); return ide_started; } -static ide_startstop_t pre_bio_out_intr(ide_drive_t *drive, struct request *rq) +static ide_startstop_t pre_task_mulout_intr(ide_drive_t *drive, struct request *rq) { ide_task_t *args = rq->special; ide_startstop_t startstop; - /* - * assign private copy for multi-write - */ - memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request)); - - if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) + 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->addressing ? "MULTWRITE_EXT" : "MULTWRITE"); return startstop; - + } +#if 0 + if (wait_for_ready(drive, 100)) + BUG(); +#else ata_poll_drive_ready(drive); - return args->handler(drive); -} - - -static ide_startstop_t bio_mulout_intr (ide_drive_t *drive) -{ - byte stat = GET_STAT(); - byte io_32bit = drive->io_32bit; - struct request *rq = &HWGROUP(drive)->wrq; - ide_hwgroup_t *hwgroup = HWGROUP(drive); - int mcount = drive->mult_count; - ide_startstop_t startstop; - +#endif /* - * (ks/hs): Handle last IRQ on multi-sector transfer, - * occurs after all data was sent in this chunk + * WARNING :: if the drive as not acked good status we may not + * move the DATA-TRANSFER T-Bar as BSY != 0. */ - if (!rq->nr_sectors) { - if (stat & (ERR_STAT|DRQ_STAT)) { - startstop = ide_error(drive, "bio_mulout_intr", stat); - memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request)); - return startstop; - } - - __ide_end_request(drive, 1, rq->hard_nr_sectors); - HWGROUP(drive)->wrq.bio = NULL; - return ide_stopped; - } - - if (!OK_STAT(stat, DATA_READY, BAD_R_STAT)) { - if (stat & (ERR_STAT | DRQ_STAT)) { - startstop = ide_error(drive, "bio_mulout_intr", stat); - memcpy(rq, HWGROUP(drive)->rq, sizeof(struct request)); - return startstop; - } - - /* no data yet, so wait for another interrupt */ - if (hwgroup->handler == NULL) - ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL); - - return ide_started; - } - - do { - char *buffer; - int nsect = rq->current_nr_sectors; - unsigned long flags; - - if (nsect > mcount) - nsect = mcount; - mcount -= nsect; - - buffer = bio_kmap_irq(rq->bio, &flags) + ide_rq_offset(rq); - rq->sector += nsect; - rq->nr_sectors -= nsect; - rq->current_nr_sectors -= nsect; - - /* Do we move to the next bio after this? */ - if (!rq->current_nr_sectors) { - /* remember to fix this up /jens */ - struct bio *bio = rq->bio->bi_next; - - /* end early early we ran out of requests */ - if (!bio) { - mcount = 0; - } else { - rq->bio = bio; - rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9; - } - } - - /* - * Ok, we're all setup for the interrupt - * re-entering us on the last transfer. - */ - taskfile_output_data(drive, buffer, nsect * SECTOR_WORDS); - bio_kunmap_irq(buffer, &flags); - } while (mcount); - - drive->io_32bit = io_32bit; - rq->errors = 0; - if (hwgroup->handler == NULL) - ide_set_handler(drive, bio_mulout_intr, WAIT_CMD, NULL); - - return ide_started; + return args->handler(drive); } /* * Handler for command with Read Multiple */ +/* + * FIXME before 2.6 ... DATA integrity issue upon error. + */ static ide_startstop_t task_mulin_intr(ide_drive_t *drive) { - unsigned int msect, nsect; byte stat = GET_STAT(); byte io_32bit = drive->io_32bit; struct request *rq = HWGROUP(drive)->rq; char *pBuf = NULL; + unsigned int msect = drive->mult_count; + unsigned int nsect; unsigned long flags; if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { if (stat & (ERR_STAT|DRQ_STAT)) { + printk("%s: MULTI-READ assume all data transfered " \ + "is bad status=0x%02x\n", + drive->name, stat); return ide_error(drive, "task_mulin_intr", stat); } /* no data yet, so wait for another interrupt */ - ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL); + if (HWGROUP(drive)->handler == NULL) + ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); return ide_started; } - /* (ks/hs): Fixed Multi-Sector transfer */ - msect = drive->mult_count; - do { nsect = rq->current_nr_sectors; if (nsect > msect) nsect = msect; - pBuf = ide_map_rq(rq, &flags); - - DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n", - pBuf, nsect, rq->current_nr_sectors); + DTF("Multiread: %p, nsect: %d, msect: %d, " \ + " rq->current_nr_sectors: %d\n", + pBuf, nsect, msect, rq->current_nr_sectors); drive->io_32bit = 0; taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); ide_unmap_rq(rq, pBuf, &flags); @@ -762,12 +764,8 @@ return ide_stopped; } } while (msect); - - - /* - * more data left - */ - ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL); + if (HWGROUP(drive)->handler == NULL) + ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL); return ide_started; } @@ -778,6 +776,9 @@ args->prehandler = NULL; args->handler = NULL; +#if 0 + args->posthandler = NULL; /* put this back in or BUGS will happen */ +#endif switch(args->tfRegister[IDE_COMMAND_OFFSET]) { case WIN_IDENTIFY: @@ -814,8 +815,8 @@ case CFA_WRITE_MULTI_WO_ERASE: case WIN_MULTWRITE: case WIN_MULTWRITE_EXT: - args->prehandler = pre_bio_out_intr; - args->handler = bio_mulout_intr; + args->prehandler = pre_task_mulout_intr; + args->handler = task_mulout_intr; args->command_type = IDE_DRIVE_TASK_RAW_WRITE; return; @@ -1063,6 +1064,9 @@ * * The caller has to make sure buf is never NULL! */ +/* + * FIXME before 2.6, this needs to map into at taskfile. + */ static int ide_wait_cmd(ide_drive_t *drive, int cmd, int nsect, int feature, int sectors, byte *argbuf) { struct request rq; @@ -1080,6 +1084,9 @@ return ide_do_drive_cmd(drive, &rq, ide_wait); } +/* + * FIXME before 2.6, this needs to map into at taskfile. + */ int ide_cmd_ioctl(ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; @@ -1133,6 +1140,9 @@ return err; } +/* + * FIXME before 2.6, this needs to map into at taskfile. + */ int ide_task_ioctl (ide_drive_t *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int err = 0; diff -urN linux-2.5.7/drivers/ide/ide.c linux-2.5.7.fix/drivers/ide/ide.c --- linux-2.5.7/drivers/ide/ide.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/ide.c Sat Mar 23 01:22:41 2002 @@ -549,6 +549,8 @@ printk("%s: ATAPI reset complete\n", drive->name); } else { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); return ide_started; /* continue polling */ } @@ -574,6 +576,8 @@ if (!OK_STAT(tmp=GET_STAT(), 0, BUSY_STAT)) { if (0 < (signed long)(hwgroup->poll_timeout - jiffies)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); return ide_started; /* continue polling */ } @@ -645,6 +649,8 @@ udelay (20); OUT_BYTE (WIN_SRST, IDE_COMMAND_REG); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &atapi_reset_pollfunc, HZ/20, NULL); __restore_flags (flags); /* local CPU only */ return ide_started; @@ -679,6 +685,8 @@ } udelay(10); /* more than enough time */ hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &reset_pollfunc, HZ/20, NULL); /* @@ -933,6 +941,9 @@ */ void ide_cmd (ide_drive_t *drive, byte cmd, byte nsect, ide_handler_t *handler) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); + ide_set_handler (drive, handler, WAIT_CMD, NULL); if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl,IDE_CONTROL_REG); /* clear nIEN */ diff -urN linux-2.5.7/drivers/ide/pdc4030.c linux-2.5.7.fix/drivers/ide/pdc4030.c --- linux-2.5.7/drivers/ide/pdc4030.c Fri Mar 22 02:58:00 2002 +++ linux-2.5.7.fix/drivers/ide/pdc4030.c Sat Mar 23 01:28:41 2002 @@ -394,6 +394,9 @@ if (GET_STAT() & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { + + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); return ide_started; /* continue polling... */ } @@ -476,6 +479,7 @@ if (IN_BYTE(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ BUG(); ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); return ide_started; /* continue polling... */ } @@ -489,6 +493,8 @@ */ promise_multwrite(drive, 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + 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", @@ -523,6 +529,8 @@ if (promise_multwrite(drive, rq->nr_sectors - 4)) return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler (drive, &promise_write_pollfunc, HZ/100, NULL); return ide_started; } else { @@ -533,6 +541,8 @@ if (promise_multwrite(drive, rq->nr_sectors)) return ide_stopped; hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &promise_complete_pollfunc, HZ/100, NULL); #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: promise_write: <= 4 sectors, " @@ -554,6 +564,13 @@ unsigned long timeout; byte stat; + /* Check that it's a regular command. If not, bomb out early. */ + if (!(rq->flags & REQ_CMD)) { + blk_dump_rq_flags(rq, "pdc4030 bad flags"); + ide_end_request(drive, 0); + return ide_stopped; + } + if (IDE_CONTROL_REG) OUT_BYTE(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ SELECT_MASK(HWIF(drive), drive, 0); @@ -568,16 +585,8 @@ OUT_BYTE(taskfile->device_head, IDE_SELECT_REG); OUT_BYTE(taskfile->command, IDE_COMMAND_REG); -/* Check that it's a regular command. If not, bomb out early. */ - if (!(rq->flags & REQ_CMD)) { - blk_dump_rq_flags(rq, "pdc4030 bad flags"); - ide_end_request(drive, 0); - return ide_stopped; - } - switch (rq_data_dir(rq)) { case READ: - OUT_BYTE(PROMISE_READ, IDE_COMMAND_REG); /* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be @@ -600,6 +609,8 @@ printk(KERN_DEBUG "%s: read: waiting for " "interrupt\n", drive->name); #endif + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &promise_read_intr, WAIT_CMD, NULL); return ide_started; } @@ -612,7 +623,6 @@ case WRITE: { ide_startstop_t startstop; - OUT_BYTE(PROMISE_WRITE, IDE_COMMAND_REG); /* * Strategy on write is: * look for the DRQ that should have been immediately asserted diff -urN linux-2.5.7/drivers/ide/trm290.c linux-2.5.7.fix/drivers/ide/trm290.c --- linux-2.5.7/drivers/ide/trm290.c Thu Mar 7 18:18:16 2002 +++ linux-2.5.7.fix/drivers/ide/trm290.c Sat Mar 23 01:29:29 2002 @@ -194,6 +194,8 @@ outw((count * 2) - 1, hwif->dma_base+2); /* start DMA */ if (drive->type != ATA_DISK) return 0; + if (HWGROUP(drive)->handler != NULL) /* paranoia check */ + BUG(); ide_set_handler(drive, &ide_dma_intr, WAIT_CMD, NULL); OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG); return 0;