lkml.org 
[lkml]   [2003]   [Mar]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] new IDE PIO handlers 1/4

# Rewritten PIO handlers, both single and multiple sector sizes.
#
# They make use of new bio travelsing code and are supposed to be
# correct in respect to ATA state machine.
#
# Patch 1/4 - Implement them, do not activate yet.
# Fix do_rw_taskfile() and flagged_taskfile() for correct
# handling of new prehandlers.
#
# Bartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl>

diff -uNr linux-2.5.66/drivers/ide/ide-taskfile.c linux/drivers/ide/ide-taskfile.c
--- linux-2.5.66/drivers/ide/ide-taskfile.c Tue Mar 25 22:53:09 2003
+++ linux/drivers/ide/ide-taskfile.c Wed Mar 26 22:49:34 2003
@@ -5,6 +5,7 @@
* Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
* Copyright (C) 2001-2002 Klaus Smolin
* IBM Storage Technology Division
+ * Copyright (C) 2003 Bartlomiej Zolnierkiewicz
*
* The big the bad and the ugly.
*
@@ -176,9 +177,12 @@

hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG);
if (task->handler != NULL) {
- ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
- if (task->prehandler != NULL)
+ if (task->prehandler != NULL) {
+ hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
+ ndelay(400); /* FIXME */
return task->prehandler(drive, task->rq);
+ }
+ ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
return ide_started;
}

@@ -535,6 +539,262 @@

EXPORT_SYMBOL(task_no_data_intr);

+#define PIO_IN 0
+#define PIO_OUT 1
+
+static inline void task_sectors(ide_drive_t *drive, struct request *rq,
+ unsigned nsect, int rw)
+{
+ unsigned long flags;
+ char *buf;
+
+ buf = task_map_rq(rq, &flags);
+
+ /*
+ * IRQ can happen instantly after reading/writing
+ * last sector of the datablock.
+ */
+ process_that_request_first(rq, nsect);
+
+ if (rw == PIO_OUT)
+ taskfile_output_data(drive, buf, nsect * SECTOR_WORDS);
+ else
+ taskfile_input_data(drive, buf, nsect * SECTOR_WORDS);
+
+ task_unmap_rq(rq, buf, &flags);
+}
+
+/*
+ * Handler for command with PIO data-in phase (Read).
+ */
+ide_startstop_t task_in_intr (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ u8 stat, good_stat;
+
+ good_stat = DATA_READY;
+check_status:
+ stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ if (!OK_STAT(stat, good_stat, BAD_R_STAT)) {
+ if (stat & (ERR_STAT|DRQ_STAT))
+ return DRIVER(drive)->error(drive, __FUNCTION__, stat);
+ /* No data yet, so wait for another IRQ. */
+ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+ return ide_started;
+ }
+
+ /*
+ * Complete previously submitted bios (if any).
+ * Status was already verifyied.
+ */
+ while (rq->hard_bio != rq->bio)
+ if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->hard_bio)))
+ return ide_stopped;
+
+ rq->errors = 0;
+ task_sectors(drive, rq, 1, PIO_IN);
+
+ /* If it was the last datablock check status and finish transfer. */
+ if (!rq->nr_sectors) {
+ good_stat = 0;
+ goto check_status;
+ }
+
+ /* Still data left to transfer. */
+ ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL);
+
+ return ide_started;
+}
+
+EXPORT_SYMBOL(task_in_intr);
+
+/*
+ * Handler for command with PIO data-in phase (Read Multiple).
+ */
+ide_startstop_t task_mulin_intr (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned int msect = drive->mult_count;
+ unsigned int nsect;
+ u8 stat, good_stat;
+
+ good_stat = DATA_READY;
+check_status:
+ stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ if (!OK_STAT(stat, good_stat, BAD_R_STAT)) {
+ if (stat & (ERR_STAT|DRQ_STAT))
+ return DRIVER(drive)->error(drive, __FUNCTION__, stat);
+ /* No data yet, so wait for another IRQ. */
+ ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
+ return ide_started;
+ }
+
+ /*
+ * Complete previously submitted bios (if any).
+ * Status was already verifyied.
+ */
+ while (rq->hard_bio != rq->bio)
+ if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->hard_bio)))
+ return ide_stopped;
+
+ rq->errors = 0;
+ do {
+ nsect = rq->current_nr_sectors;
+ if (nsect > msect)
+ nsect = msect;
+
+ task_sectors(drive, rq, nsect, PIO_IN);
+
+ if (!rq->nr_sectors)
+ msect = 0;
+ else
+ msect -= nsect;
+ } while (msect);
+
+ /* If it was the last datablock check status and finish transfer. */
+ if (!rq->nr_sectors) {
+ good_stat = 0;
+ goto check_status;
+ }
+
+ /* Still data left to transfer. */
+ ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL);
+
+ return ide_started;
+}
+
+EXPORT_SYMBOL(task_mulin_intr);
+
+/*
+ * Handler for command with PIO data-out phase (Write).
+ */
+ide_startstop_t task_out_intr (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ u8 stat;
+ int ok_stat;
+
+ stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ ok_stat = OK_STAT(stat, DRIVE_READY, drive->bad_wstat);
+
+ if (!ok_stat || !rq->nr_sectors) {
+ if (stat & (ERR_STAT|DRQ_STAT))
+ return DRIVER(drive)->error(drive, __FUNCTION__, stat);
+ if (stat & BUSY_STAT) {
+ /* Not ready yet, so wait for another IRQ. */
+ ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
+ return ide_started;
+ }
+ }
+
+ /*
+ * Complete previously submitted bios (if any).
+ * Status was already verifyied.
+ */
+ while (rq->hard_bio != rq->bio)
+ if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->hard_bio)))
+ return ide_stopped;
+
+ /* Still data left to transfer. */
+ ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);
+
+ rq->errors = 0;
+ task_sectors(drive, rq, 1, PIO_OUT);
+
+ 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;
+
+ if (ide_wait_stat(&startstop, drive, DATA_READY,
+ drive->bad_wstat, WAIT_DRQ)) {
+ printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n",
+ drive->name, drive->addressing ? "_EXT" : "");
+ return startstop;
+ }
+
+ return task_out_intr(drive);
+}
+
+EXPORT_SYMBOL(pre_task_out_intr);
+
+/*
+ * Handler for command with PIO data-out phase (Write Multiple).
+ */
+ide_startstop_t task_mulout_intr (ide_drive_t *drive)
+{
+ struct request *rq = HWGROUP(drive)->rq;
+ unsigned int msect = drive->mult_count;
+ unsigned int nsect;
+ u8 stat;
+ int ok_stat;
+
+ stat = HWIF(drive)->INB(IDE_STATUS_REG);
+ ok_stat = OK_STAT(stat, DRIVE_READY, drive->bad_wstat);
+
+ if (!ok_stat || !rq->nr_sectors) {
+ if (stat & (ERR_STAT|DRQ_STAT))
+ return DRIVER(drive)->error(drive, __FUNCTION__, stat);
+ if (stat & BUSY_STAT) {
+ /* Not ready yet, so wait for another IRQ. */
+ ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
+ return ide_started;
+ }
+ }
+
+ /*
+ * Complete previously submitted bios (if any).
+ * Status was already verifyied.
+ */
+ while (rq->hard_bio != rq->bio)
+ if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->hard_bio)))
+ return ide_stopped;
+
+ /* Still data left to transfer. */
+ ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL);
+
+ rq->errors = 0;
+ do {
+ nsect = rq->current_nr_sectors;
+ if (nsect > msect)
+ nsect = msect;
+
+ task_sectors(drive, rq, nsect, PIO_OUT);
+
+ if (!rq->nr_sectors)
+ msect = 0;
+ else
+ msect -= nsect;
+
+ } while (msect);
+
+ return ide_started;
+}
+
+EXPORT_SYMBOL(task_mulout_intr);
+
+ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq)
+{
+ 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 MULTWRITE%s\n",
+ drive->name, drive->addressing ? "_EXT" : "");
+ return startstop;
+ }
+
+ return task_mulout_intr(drive);
+}
+
+EXPORT_SYMBOL(pre_task_mulout_intr);
+
+
+#if 0
/*
* Handler for command with PIO data-in phase, READ
*/
@@ -932,6 +1192,7 @@
}

EXPORT_SYMBOL(task_mulout_intr);
+#endif /* 0 */

/* Called by internal to feature out type of command being called */
//ide_pre_handler_t * ide_pre_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile)
@@ -1873,10 +2134,14 @@
if (task->handler == NULL)
return ide_stopped;

+ if (task->prehandler != NULL) {
+ hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);
+ ndelay(400); /* FIXME */
+ return task->prehandler(drive, HWGROUP(drive)->rq);
+ }
+
/* Issue the command */
ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);
- if (task->prehandler != NULL)
- return task->prehandler(drive, HWGROUP(drive)->rq);
}

return ide_started;

-
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/

\
 
 \ /
  Last update: 2005-03-22 13:34    [W:0.105 / U:0.096 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site