[patch] 2.5.3-pre1 ide updates

Jens Axboe (axboe@suse.de)
Thu, 17 Jan 2002 14:46:48 +0100


Hi,

The following patch makes IDE pio and multi mode work again. Changes:

- Properly map in requests, nr_sectors hack was very wrong (me)

- Fix pio interrupt handlers to handle requests properly (me)

- Fix task_mulout_intr to handle requests in chunks of
current_nr_sectors, regardless of set multi count. This both makes it
work, but also ensures we do not have to fall back to same hackish
'copy-of-rq' approach that 2.4 uses. It comes at the cost of handling
fs block size number of sectors at the time instead of max multi
count, but I think this is a price worth paying. It's miniscule
anyway. (me)

- Fix task_mulin_intr to properly loop and handle as many sectors as we
set up (multi count or nr_sectors, whichever is smallest) (me)

- Fix wrong isr for multi mode enable, caused hdparm hang (Andre)

- ide-disk.c:do_rw_disk() had wrong check of rq flags, couldn't catch
anything (either the bit is set or not, checking both makes no sense).
Check for fs request there instead. (me)

- ide_dma_timeout_retry(), set correct next current_nr_sectors and only
for bio request. (me)

- ll_rw_blk, blk_dump_rq_flags wasn't properly adjusted for new IDE
flag (me)

diff -urN -X exclude /ata/linux-2.5.3-pre1/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- /ata/linux-2.5.3-pre1/drivers/block/ll_rw_blk.c Thu Jan 10 19:15:38 2002
+++ linux/drivers/block/ll_rw_blk.c Wed Jan 16 04:01:52 2002
@@ -302,8 +303,8 @@
static char *rq_flags[] = { "REQ_RW", "REQ_RW_AHEAD", "REQ_BARRIER",
"REQ_CMD", "REQ_NOMERGE", "REQ_STARTED",
"REQ_DONTPREP", "REQ_DRIVE_CMD", "REQ_DRIVE_TASK",
- "REQ_PC", "REQ_BLOCK_PC", "REQ_SENSE",
- "REQ_SPECIAL" };
+ "REQ_DRIVE_ACB", "REQ_PC", "REQ_BLOCK_PC",
+ "REQ_SENSE", "REQ_SPECIAL" };

void blk_dump_rq_flags(struct request *rq, char *msg)
{
diff -urN -X exclude /ata/linux-2.5.3-pre1/drivers/ide/ide-disk.c linux/drivers/ide/ide-disk.c
--- /ata/linux-2.5.3-pre1/drivers/ide/ide-disk.c Thu Jan 17 06:32:54 2002
+++ linux/drivers/ide/ide-disk.c Thu Jan 17 03:53:09 2002
@@ -123,12 +123,10 @@
*/
static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
- if (rq_data_dir(rq) == READ)
- goto good_command;
- if (rq_data_dir(rq) == WRITE)
+ if (rq->flags & REQ_CMD)
goto good_command;

- printk(KERN_ERR "%s: bad command: %lx\n", drive->name, rq->flags);
+ blk_dump_rq_flags(rq, "do_rw_disk, bad command");
ide_end_request(0, HWGROUP(drive));
return ide_stopped;

@@ -179,8 +177,10 @@
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
ide_task_t args;
+ int sectors;

task_ioreg_t command = get_command(drive, rq_data_dir(rq));
+
unsigned int track = (block / drive->sect);
unsigned int sect = (block % drive->sect) + 1;
unsigned int head = (track % drive->head);
@@ -189,7 +189,16 @@
memset(&taskfile, 0, sizeof(task_struct_t));
memset(&hobfile, 0, sizeof(hob_struct_t));

- taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+ sectors = rq->nr_sectors;
+ if (sectors == 256)
+ sectors = 0;
+ if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+ sectors = drive->mult_count;
+ if (sectors > rq->current_nr_sectors)
+ sectors = rq->current_nr_sectors;
+ }
+
+ taskfile.sector_count = sectors;
taskfile.sector_number = sect;
taskfile.low_cylinder = cyl;
taskfile.high_cylinder = (cyl>>8);
@@ -225,13 +234,23 @@
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
ide_task_t args;
+ int sectors;

task_ioreg_t command = get_command(drive, rq_data_dir(rq));

+ sectors = rq->nr_sectors;
+ if (sectors == 256)
+ sectors = 0;
+ if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+ sectors = drive->mult_count;
+ if (sectors > rq->current_nr_sectors)
+ sectors = rq->current_nr_sectors;
+ }
+
memset(&taskfile, 0, sizeof(task_struct_t));
memset(&hobfile, 0, sizeof(hob_struct_t));

- taskfile.sector_count = (rq->nr_sectors==256)?0x00:rq->nr_sectors;
+ taskfile.sector_count = sectors;
taskfile.sector_number = block;
taskfile.low_cylinder = (block>>=8);
taskfile.high_cylinder = (block>>=8);
@@ -273,14 +292,24 @@
struct hd_drive_task_hdr taskfile;
struct hd_drive_hob_hdr hobfile;
ide_task_t args;
+ int sectors;

task_ioreg_t command = get_command(drive, rq_data_dir(rq));

memset(&taskfile, 0, sizeof(task_struct_t));
memset(&hobfile, 0, sizeof(hob_struct_t));

- taskfile.sector_count = rq->nr_sectors;
- hobfile.sector_count = (rq->nr_sectors>>8);
+ sectors = rq->nr_sectors;
+ if (sectors == 256)
+ sectors = 0;
+ if (command == WIN_MULTWRITE_EXT || command == WIN_MULTWRITE) {
+ sectors = drive->mult_count;
+ if (sectors > rq->current_nr_sectors)
+ sectors = rq->current_nr_sectors;
+ }
+
+ taskfile.sector_count = sectors;
+ hobfile.sector_count = sectors >> 8;

if (rq->nr_sectors == 65536) {
taskfile.sector_count = 0x00;
@@ -652,7 +681,7 @@
memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
taskfile.sector_count = drive->mult_req;
taskfile.command = WIN_SETMULT;
- do_taskfile(drive, &taskfile, &hobfile, ide_handler_parser(&taskfile, &hobfile));
+ do_taskfile(drive, &taskfile, &hobfile, &set_multmode_intr);
}
} else if (s->all) {
int special = s->all;
@@ -789,23 +818,12 @@

#endif /* CONFIG_PROC_FS */

+/*
+ * This is tightly woven into the driver->do_special can not touch.
+ * DON'T do it again until a total personality rewrite is committed.
+ */
static int set_multcount(ide_drive_t *drive, int arg)
{
-#if 1
- struct hd_drive_task_hdr taskfile;
- struct hd_drive_hob_hdr hobfile;
-
- if (drive->special.b.set_multmode)
- return -EBUSY;
-
- memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr));
- memset(&hobfile, 0, sizeof(struct hd_drive_hob_hdr));
- taskfile.sector_count = drive->mult_req;
- taskfile.command = WIN_SETMULT;
- drive->mult_req = arg;
- drive->special.b.set_multmode = 1;
- ide_wait_taskfile(drive, &taskfile, &hobfile, NULL);
-#else
struct request rq;

if (drive->special.b.set_multmode)
@@ -814,7 +832,6 @@
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
(void) ide_do_drive_cmd (drive, &rq, ide_wait);
-#endif
return (drive->mult_count == arg) ? 0 : -EIO;
}

diff -urN -X exclude /ata/linux-2.5.3-pre1/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- /ata/linux-2.5.3-pre1/drivers/ide/ide-taskfile.c Thu Jan 17 06:32:54 2002
+++ linux/drivers/ide/ide-taskfile.c Thu Jan 17 06:29:13 2002
@@ -706,8 +706,8 @@
ide__sti(); /* local CPU only */

if (!OK_STAT(stat, READY_STAT, BAD_STAT))
- return ide_error(drive, "task_no_data_intr", stat); /* calls ide_end_drive_cmd */
-
+ return ide_error(drive, "task_no_data_intr", stat);
+ /* calls ide_end_drive_cmd */
if (args)
ide_end_drive_cmd (drive, stat, GET_ERR());

@@ -723,6 +723,7 @@
byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
+ unsigned long flags;

if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
if (stat & (ERR_STAT|DRQ_STAT)) {
@@ -735,17 +736,21 @@
}
}
DTF("stat: %02x\n", stat);
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ pBuf = ide_map_rq(rq, &flags);
DTF("Read: %p, rq->current_nr_sectors: %d\n", pBuf, (int) rq->current_nr_sectors);

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());
- ide_end_request(1, HWGROUP(drive));
+ if (ide_end_request(1, HWGROUP(drive))) {
+ ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
} else {
ide_set_handler(drive, &task_in_intr, WAIT_CMD, NULL);
return ide_started;
@@ -809,13 +814,14 @@
byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
+ unsigned long flags;

if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) {
if (stat & (ERR_STAT|DRQ_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);
+ ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
return ide_started;
}

@@ -834,10 +840,11 @@
*/
nsect = 1;
while (rq->current_nr_sectors) {
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ pBuf = ide_map_rq(rq, &flags);
DTF("Multiread: %p, nsect: %d, rq->current_nr_sectors: %ld\n", pBuf, nsect, rq->current_nr_sectors);
drive->io_32bit = 0;
taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+ ide_unmap_rq(rq, pBuf, &flags);
drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors -= nsect;
@@ -848,22 +855,38 @@
}
#endif /* ALTSTAT_SCREW_UP */

- nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ do {
+ nsect = rq->current_nr_sectors;
+ if (nsect > msect)
+ nsect = msect;

- DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
- pBuf, nsect, rq->current_nr_sectors);
- drive->io_32bit = 0;
- taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
- drive->io_32bit = io_32bit;
- rq->errors = 0;
- rq->current_nr_sectors -= nsect;
- if (rq->current_nr_sectors != 0) {
- ide_set_handler(drive, &task_mulin_intr, WAIT_CMD, NULL);
- return ide_started;
- }
- ide_end_request(1, HWGROUP(drive));
- return ide_stopped;
+ pBuf = ide_map_rq(rq, &flags);
+
+ DTF("Multiread: %p, nsect: %d , rq->current_nr_sectors: %ld\n",
+ pBuf, nsect, rq->current_nr_sectors);
+ drive->io_32bit = 0;
+ taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS);
+ ide_unmap_rq(rq, pBuf, &flags);
+ drive->io_32bit = io_32bit;
+ rq->errors = 0;
+ rq->current_nr_sectors -= nsect;
+ msect -= nsect;
+ if (!rq->current_nr_sectors) {
+ if (!ide_end_request(1, HWGROUP(drive)))
+ return ide_stopped;
+ }
+ } while (msect);
+
+#if 0
+ if (!ide_end_request(1, HWGROUP(drive)))
+ return ide_stopped;
+#endif
+
+ /*
+ * more data left
+ */
+ ide_set_handler(drive, task_mulin_intr, WAIT_CMD, NULL);
+ return ide_started;
}

ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq)
@@ -879,10 +902,12 @@
/* (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, rq->buffer, SECTOR_WORDS);
+ taskfile_output_data(drive, buf, SECTOR_WORDS);
rq->current_nr_sectors--;
- return ide_started;
+ ide_unmap_rq(rq, buf, &flags);
} else {
/*
* (ks/hs): Stuff the first sector(s)
@@ -913,8 +938,10 @@
byte io_32bit = drive->io_32bit;
struct request *rq = HWGROUP(drive)->rq;
char *pBuf = NULL;
+ unsigned long flags;

if (!rq->current_nr_sectors) {
+ printk("task_out_intr: should not trigger\n");
ide_end_request(1, HWGROUP(drive));
return ide_stopped;
}
@@ -922,19 +949,24 @@
if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) {
return ide_error(drive, "task_out_intr", stat);
}
+
if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) {
rq = HWGROUP(drive)->rq;
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ pBuf = ide_map_rq(rq, &flags);
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);
drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors--;
}

if (rq->current_nr_sectors <= 0) {
- ide_end_request(1, HWGROUP(drive));
+ if (ide_end_request(1, HWGROUP(drive))) {
+ ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
+ return ide_started;
+ }
} else {
ide_set_handler(drive, &task_out_intr, WAIT_CMD, NULL);
return ide_started;
@@ -961,14 +993,20 @@
struct request *rq = HWGROUP(drive)->rq;
ide_hwgroup_t *hwgroup = HWGROUP(drive);
char *pBuf = NULL;
+ unsigned long flags;

/*
* (ks/hs): Handle last IRQ on multi-sector transfer,
- * occurs after all data was sent
+ * occurs after all data was sent in this chunk
*/
if (rq->current_nr_sectors == 0) {
if (stat & (ERR_STAT|DRQ_STAT))
return ide_error(drive, "task_mulout_intr", stat);
+
+ /*
+ * there may be more, ide_do_request will restart it if
+ * necessary
+ */
ide_end_request(1, HWGROUP(drive));
return ide_stopped;
}
@@ -994,10 +1032,11 @@
if (!msect) {
nsect = 1;
while (rq->current_nr_sectors) {
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ pBuf = ide_unmap_buffer(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_buffer(pBuf, &flags);
drive->io_32bit = io_32bit;
rq->errors = 0;
rq->current_nr_sectors -= nsect;
@@ -1008,12 +1047,16 @@
}
#endif /* ALTSTAT_SCREW_UP */

- nsect = (rq->current_nr_sectors > msect) ? msect : rq->current_nr_sectors;
- pBuf = rq->buffer + ((rq->nr_sectors - rq->current_nr_sectors) * SECTOR_SIZE);
+ nsect = rq->current_nr_sectors;
+ if (nsect > msect)
+ nsect = msect;
+
+ 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;
rq->errors = 0;
rq->current_nr_sectors -= nsect;
diff -urN -X exclude /ata/linux-2.5.3-pre1/drivers/ide/ide.c linux/drivers/ide/ide.c
--- /ata/linux-2.5.3-pre1/drivers/ide/ide.c Thu Jan 17 06:32:54 2002
+++ linux/drivers/ide/ide.c Thu Jan 17 03:07:23 2002
@@ -1458,14 +1458,11 @@
HWGROUP(drive)->rq = NULL;

rq->errors = 0;
- rq->sector = rq->bio->bi_sector;
- rq->current_nr_sectors = bio_sectors(rq->bio);
-
- /*
- * just to make sure...
- */
- if (rq->bio)
+ if (rq->bio) {
+ rq->sector = rq->bio->bi_sector;
+ rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
rq->buffer = NULL;
+ }
}

/*
diff -urN -X exclude /ata/linux-2.5.3-pre1/include/linux/ide.h linux/include/linux/ide.h
--- /ata/linux-2.5.3-pre1/include/linux/ide.h Thu Jan 17 06:32:55 2002
+++ linux/include/linux/ide.h Thu Jan 17 03:22:45 2002
@@ -884,6 +884,9 @@
*/
#define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)

+#define task_rq_offset(rq) \
+ (((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE)
+
extern inline void *ide_map_buffer(struct request *rq, unsigned long *flags)
{
return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq);
@@ -892,6 +895,24 @@
extern inline void ide_unmap_buffer(char *buffer, unsigned long *flags)
{
bio_kunmap_irq(buffer, flags);
+}
+
+/*
+ * for now, taskfile requests are special :/
+ */
+extern inline char *ide_map_rq(struct request *rq, unsigned long *flags)
+{
+ if (rq->bio)
+ return ide_map_buffer(rq, flags);
+ else
+ return rq->buffer + task_rq_offset(rq);
+}
+
+extern inline void ide_unmap_rq(struct request *rq, char *buf,
+ unsigned long *flags)
+{
+ if (rq->bio)
+ ide_unmap_buffer(buf, flags);
}

/*

-- 
Jens Axboe

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/