Commit f55ae64b authored by Jens Axboe's avatar Jens Axboe Committed by Linus Torvalds

[PATCH] ide tcq fixes

This fixes a few problems with ide tcq, I don't know of any other known
ones (and it is solid here, survives ours of beating on it). Basically:

- Don't enable tcq if the drive isn't alone on the channel. This raises
  all sorts of fun that really requires hardware support (auto poll), or
  it's going to _suck_. I never wanted to do that, and no hardware I
  know of supports auto-poll.

- Introduce a drive blacklist so we don't enable tcq on known broken
  drives. Or enable with restrictions on some models.

- Add a check for pdc4030, apparently tcq doesn't work there (hell knows
  who would be crazy enough to pull such a stunt).
parent a9a5b952
...@@ -51,9 +51,58 @@ ...@@ -51,9 +51,58 @@
*/ */
#undef IDE_TCQ_FIDDLE_SI #undef IDE_TCQ_FIDDLE_SI
/*
* bad drive blacklist, for drives that raport tcq capability but don't
* work reliably with the default config. initially from freebsd table.
*/
struct ide_tcq_blacklist {
char *model;
char works;
unsigned int max_sectors;
};
static struct ide_tcq_blacklist ide_tcq_blacklist[] = {
{
.model = "IBM-DTTA",
.works = 1,
.max_sectors = 128,
},
{
.model = "IBM-DJNA",
.works = 0,
},
{
.model = "WDC AC",
.works = 0,
},
{
.model = NULL,
},
};
ide_startstop_t ide_dmaq_intr(ide_drive_t *drive); ide_startstop_t ide_dmaq_intr(ide_drive_t *drive);
ide_startstop_t ide_service(ide_drive_t *drive); ide_startstop_t ide_service(ide_drive_t *drive);
static struct ide_tcq_blacklist *ide_find_drive_blacklist(ide_drive_t *drive)
{
struct ide_tcq_blacklist *itb;
int i = 0;
do {
itb = &ide_tcq_blacklist[i];
if (!itb->model)
break;
if (!strncmp(drive->id->model, itb->model, strlen(itb->model)))
return itb;
i++;
} while (1);
return NULL;
}
static inline void drive_ctl_nien(ide_drive_t *drive, int set) static inline void drive_ctl_nien(ide_drive_t *drive, int set)
{ {
#ifdef IDE_TCQ_NIEN #ifdef IDE_TCQ_NIEN
...@@ -502,7 +551,7 @@ static int ide_tcq_configure(ide_drive_t *drive) ...@@ -502,7 +551,7 @@ static int ide_tcq_configure(ide_drive_t *drive)
return 0; return 0;
err: err:
kfree(args); kfree(args);
return 1; return -EIO;
} }
/* /*
...@@ -511,6 +560,7 @@ static int ide_tcq_configure(ide_drive_t *drive) ...@@ -511,6 +560,7 @@ static int ide_tcq_configure(ide_drive_t *drive)
*/ */
static int ide_enable_queued(ide_drive_t *drive, int on) static int ide_enable_queued(ide_drive_t *drive, int on)
{ {
struct ide_tcq_blacklist *itb;
int depth = drive->using_tcq ? drive->queue_depth : 0; int depth = drive->using_tcq ? drive->queue_depth : 0;
/* /*
...@@ -529,6 +579,17 @@ static int ide_enable_queued(ide_drive_t *drive, int on) ...@@ -529,6 +579,17 @@ static int ide_enable_queued(ide_drive_t *drive, int on)
return 1; return 1;
} }
/*
* some drives need limited transfer size in tcq
*/
itb = ide_find_drive_blacklist(drive);
if (itb && itb->max_sectors) {
if (itb->max_sectors > HWIF(drive)->rqsize)
itb->max_sectors = HWIF(drive)->rqsize;
blk_queue_max_sectors(&drive->queue, itb->max_sectors);
}
/* /*
* enable block tagging * enable block tagging
*/ */
...@@ -582,13 +643,36 @@ int ide_tcq_wait_dataphase(ide_drive_t *drive) ...@@ -582,13 +643,36 @@ int ide_tcq_wait_dataphase(ide_drive_t *drive)
return 0; return 0;
} }
static int ide_tcq_check_blacklist(ide_drive_t *drive)
{
struct ide_tcq_blacklist *itb = ide_find_drive_blacklist(drive);
if (!itb)
return 0;
return !itb->works;
}
int __ide_dma_queued_on(ide_drive_t *drive) int __ide_dma_queued_on(ide_drive_t *drive)
{ {
if (!drive->using_dma) if (!drive->using_dma)
return 1; return 1;
if (HWIF(drive)->chipset == ide_pdc4030)
return 1;
if (ide_tcq_check_blacklist(drive)) {
printk(KERN_WARNING "%s: tcq forbidden by blacklist\n",
drive->name);
return 1;
}
if (drive->next != drive) {
printk(KERN_WARNING "%s: only one drive on a channel supported"
" for tcq\n", drive->name);
return 1;
}
if (ata_pending_commands(drive)) { if (ata_pending_commands(drive)) {
printk(KERN_WARNING "ide-tcq; can't toggle tcq feature on busy drive\n"); printk(KERN_WARNING "ide-tcq; can't toggle tcq feature on "
"busy drive\n");
return 1; return 1;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment