こないだ失敗したCentOSのSerial ATA対応。VIA VT8251 southbridgeによると「VT8251はkernel 2.6.20でfully supported」だと言われている。
「じゃ、2.6.20.4でも動くはずやん?」と、もう一度/etc/modeprobe.confに
alias scsi_hostadapter ahciと書いてみたが、やっぱりロードされども実際動かない。こういう時は何はともあれdmesgを確認するのがはじめの一歩。
alias scsi_hostadapter1 sata_via
libata version 2.00 loaded.どうやらシリアルATAコントローラーは認識しているもののHDDとの通信エラーになっているようだ。という事がわかったところでここから先の手の打ちようが無い事には変わりない。
ahci 0000:00:0f.0: version 2.0
ACPI: PCI Interrupt 0000:00:0f.0[B] -> GSI 21 (level, low) -> IRQ 21
input: AT Translated Set 2 keyboard as /class/input/input0
ahci 0000:00:0f.0: AHCI 0001.0000 32 slots 4 ports 3 Gbps 0xf impl IDE mode
ahci 0000:00:0f.0: flags: 64bit ncq pm led clo pmp pio slum part
ata1: SATA max UDMA/133 cmd 0xFFFFC20000004D00 ctl 0x0 bmdma 0x0 irq 511
ata2: SATA max UDMA/133 cmd 0xFFFFC20000004D80 ctl 0x0 bmdma 0x0 irq 511
ata3: SATA max UDMA/133 cmd 0xFFFFC20000004E00 ctl 0x0 bmdma 0x0 irq 511
ata4: SATA max UDMA/133 cmd 0xFFFFC20000004E80 ctl 0x0 bmdma 0x0 irq 511
scsi0 : ahci
ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
APIC error on CPU0: 00(08)
APIC error on CPU1: 00(08)
ata1.00: qc timeout (cmd 0xec)
ata1.00: failed to IDENTIFY (I/O error, err_mask=0x104)
ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
APIC error on CPU0: 08(08)
APIC error on CPU1: 08(08)
ata1.00: qc timeout (cmd 0xec)
ata1.00: failed to IDENTIFY (I/O error, err_mask=0x104)
ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
APIC error on CPU0: 08(08)
APIC error on CPU1: 08(08)
ata1.00: qc timeout (cmd 0xec)
ata1.00: failed to IDENTIFY (I/O error, err_mask=0x104)
ata1: SATA link up 3.0 Gbps (SStatus 123 SControl 300)
scsi1 : ahci
ata2: SATA link down (SStatus 0 SControl 300)
scsi2 : ahci
ata3: SATA link down (SStatus 0 SControl 300)
scsi3 : ahci
ata4: SATA link down (SStatus 0 SControl 300)
今度はVIA Arena - VT8251 Linux Supportを頼りに再チャレンジ。kernel 2.6.15~17用のpatchがあるというので、ごにょごにょ2.6.17.14に適用してみたところ、うまく動いた。
dmesgを確認するとこんな感じ。
libata version 1.20 loaded.と言うわけで、2.6.20はどこかでirqを間違ってるクサいなぁ。
ahci 0000:00:0f.0: version 1.2
GSI 18 sharing vector 0xB9 and IRQ 18
ACPI: PCI Interrupt 0000:00:0f.0[B] -> GSI 21 (level, low) -> IRQ 185
input: AT Translated Set 2 keyboard as /class/input/input0
ahci 0000:00:0f.0: AHCI 0001.0000 32 slots 4 ports 3 Gbps 0xf impl IDE mode
ahci 0000:00:0f.0: flags: 64bit ncq pm led clo pmp pio slum part
ata1: SATA max UDMA/133 cmd 0xFFFFC20000004D00 ctl 0x0 bmdma 0x0 irq 201
ata2: SATA max UDMA/133 cmd 0xFFFFC20000004D80 ctl 0x0 bmdma 0x0 irq 201
ata3: SATA max UDMA/133 cmd 0xFFFFC20000004E00 ctl 0x0 bmdma 0x0 irq 201
ata4: SATA max UDMA/133 cmd 0xFFFFC20000004E80 ctl 0x0 bmdma 0x0 irq 201
ata1: SATA link up 3.0 Gbps (SStatus 123)
ata1: dev 0 cfg 49:2f00 82:746b 83:7f01 84:4023 85:7469 86:3e01 87:4023 88:407f
ata1: dev 0 ATA-7, max UDMA/133, 488397168 sectors: LBA48
ata1: dev 0 configured for UDMA/133
scsi0 : ahci
ata2: SATA link down (SStatus 0)
scsi1 : ahci
ata3: SATA link down (SStatus 0)
scsi2 : ahci
ata4: SATA link down (SStatus 0)
scsi3 : ahci
Vendor: ATA Model: WDC WD2500KS-00M Rev: 02.0
Type: Direct-Access ANSI SCSI revision: 05
SCSI device sda: 488397168 512-byte hdwr sectors (250059 MB)
sda: Write Protect is off
sda: Mode Sense: 00 3a 00 00
SCSI device sda: drive cache: write back
SCSI device sda: 488397168 512-byte hdwr sectors (250059 MB)
sda: Write Protect is off
sda: Mode Sense: 00 3a 00 00
SCSI device sda: drive cache: write back
sda: sda1
sd 0:0:0:0: Attached scsi disk sda
hdparmも
# /sbin/hdparm /dev/hdaとなっていて、パラレルATAもDMAモードになっているので問題無し。まぁ2.6.17で不都合があるわけではないので、これで良いかな。
/dev/hda:
multcount = 16 (on)
IO_support = 1 (32-bit)
unmaskirq = 1 (on)
using_dma = 1 (on)
keepsettings = 0 (off)
readonly = 0 (off)
readahead = 256 (on)
geometry = 30401/255/63, sectors = 250059350016, start = 0
試しに最新の2.6.20.4のソースを確認したのだが、ahci.cには既に同等のロジックが入っていた。どうやら2.6.19からSATAサポートがSCSIセクションからATAセクションに移動したので、そのあたりに問題が潜んでいるのかも知れない。
ちなみにVT8251用のpatchを当てたのはdrivers/scsi/ahci.cだけで、差分は以下の通り。
--- linux-2.6.17.14/drivers/scsi/ahci.c.orig 2006-10-14 03:55:04.000000000 +0900
+++ linux-2.6.17.14/drivers/scsi/ahci.c 2007-05-03 17:36:36.000000000 +0900
@@ -73,6 +73,7 @@
RX_FIS_D2H_REG = 0x40, /* offset of D2H Register FIS data */
board_ahci = 0,
+ board_ahci_vt8251 = 1,
/* global controller registers */
HOST_CAP = 0x00, /* host capabilities */
@@ -153,6 +154,9 @@
/* hpriv->flags bits */
AHCI_FLAG_MSI = (1 << 0),
+
+ /* ap->flags bits */
+ AHCI_FLAG_RESET_NEEDS_CLO = (1 << 24),
};
struct ahci_cmd_hdr {
@@ -255,6 +259,16 @@
.udma_mask = 0x7f, /* udma0-6 ; FIXME */
.port_ops = &ahci_ops,
},
+ /* board_ahci_vt8251 */
+ {
+ .sht = &ahci_sht,
+ .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA |
+ AHCI_FLAG_RESET_NEEDS_CLO,
+ .pio_mask = 0x1f, /* pio0-4 */
+ .udma_mask = 0x7f, /* udma0-6 ; FIXME */
+ .port_ops = &ahci_ops,
+ },
};
static const struct pci_device_id ahci_pci_tbl[] = {
@@ -296,6 +310,8 @@
board_ahci }, /* ATI SB600 non-raid */
{ PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
board_ahci }, /* ATI SB600 raid */
+ { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ board_ahci_vt8251 }, /* VT8251 */
{ } /* terminate list */
};
@@ -534,9 +550,27 @@
return -1;
}
-static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
+static int ahci_clo(struct ata_port *ap)
{
+ void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
struct ahci_host_priv *hpriv = ap->host_set->private_data;
+ u32 tmp;
+
+ if (!(hpriv->cap & HOST_CAP_CLO))
+ return -EOPNOTSUPP;
+
+ tmp = readl(port_mmio + PORT_CMD);
+ tmp |= PORT_CMD_CLO;
+ writel(tmp, port_mmio + PORT_CMD);
+
+ if (ahci_poll_register(port_mmio + PORT_CMD, PORT_CMD_CLO, 0x0, 1, 500))
+ return -EIO;
+
+ return 0;
+}
+
+static int ahci_softreset(struct ata_port *ap, int verbose, unsigned int *class)
+{
struct ahci_port_priv *pp = ap->private_data;
void __iomem *mmio = ap->host_set->mmio_base;
void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no);
@@ -564,23 +598,13 @@
/* check BUSY/DRQ, perform Command List Override if necessary */
ahci_tf_read(ap, &tf);
if (tf.command & (ATA_BUSY | ATA_DRQ)) {
- u32 tmp;
+ rc = ahci_clo(ap);
- if (!(hpriv->cap & HOST_CAP_CLO)) {
- rc = -EIO;
- reason = "port busy but no CLO";
+ if (rc == -EOPNOTSUPP) {
+ reason = "port busy but CLO unavailable";
goto fail_restart;
- }
-
- tmp = readl(port_mmio + PORT_CMD);
- tmp |= PORT_CMD_CLO;
- writel(tmp, port_mmio + PORT_CMD);
- readl(port_mmio + PORT_CMD); /* flush */
-
- if (ahci_poll_register(port_mmio + PORT_CMD, PORT_CMD_CLO, 0x0,
- 1, 500)) {
- rc = -EIO;
- reason = "CLO failed";
+ } else if (rc == -EIO) {
+ reason = "port busy but CLO failed";
goto fail_restart;
}
}
@@ -694,6 +718,12 @@
static int ahci_probe_reset(struct ata_port *ap, unsigned int *classes)
{
+ if ((ap->flags & AHCI_FLAG_RESET_NEEDS_CLO) &&
+ (ata_busy_wait(ap, ATA_BUSY, 1000) & ATA_BUSY)) {
+ /* ATA_BUSY hasn't cleared, so send a CLO */
+ ahci_clo(ap);
+ }
+
return ata_drive_probe_reset(ap, ata_std_probeinit,
ahci_softreset, ahci_hardreset,
ahci_postreset, classes);
【参照】
●VIA Arena Forum http://forums.viaarena.com/
┗VT8251 Linux Support 2006年4月18日
●VIA VT8251 southbridge http://via8251.la-evento.com/