From 23963ce4ed84a440237a8416b6eb9420f5a23186 Mon Sep 17 00:00:00 2001
From: Sylvian Kerjean <sylvain_kerjean@hotmail.com>
Date: Sat, 8 Aug 2015 14:43:03 -0400
Subject: [PATCH] AHCI: Fix boot failures due to "Port Connect Change" IRQ
storm.
---
src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h | 15 ++++++++-
src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp | 39 ++++++++++++++++++-----
2 files changed, 45 insertions(+), 9 deletions(-)
diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h b/src/add-ons/kernel/busses/scsi/ahci/ahci_defs.h
index c4b0101..e9d49f1 100644
a
|
b
|
enum {
|
76 | 76 | INT_DHR = (1 << 0), // Device to Host Register FIS Interrupt/Enable |
77 | 77 | }; |
78 | 78 | |
| 79 | typedef struct { |
| 80 | uint16 reserved : 12; |
| 81 | uint8 pmp : 4; // Port Multiplier Port: Not used by AHCI |
| 82 | uint8 spm : 4; // Select Power Management: Not used by AHCI |
| 83 | uint8 ipm : 4; // Interface Power Management Transitions Allowed |
| 84 | uint8 spd : 4; // Speed Allowed |
| 85 | uint8 det : 4; // Device Detection Initialization |
| 86 | } _PACKED scontrol; |
| 87 | |
| 88 | #define TRANSITIONS_TO_PARTIAL_SLUMBER_DISABLED 0x300 |
| 89 | #define NO_INITIALIZATION 0 |
| 90 | #define INITIALIZATION 1 |
| 91 | |
79 | 92 | |
80 | 93 | typedef struct { |
81 | 94 | uint32 clb; // Command List Base Address (alignment 1024 byte) |
… |
… |
typedef struct {
|
89 | 102 | uint32 tfd; // Task File Data |
90 | 103 | uint32 sig; // Signature |
91 | 104 | uint32 ssts; // Serial ATA Status (SCR0: SStatus) |
92 | | uint32 sctl; // Serial ATA Control (SCR2: SControl) |
| 105 | scontrol sctl; // Serial ATA Control (SCR2: SControl) |
93 | 106 | uint32 serr; // Serial ATA Error (SCR1: SError) **RWC** |
94 | 107 | uint32 sact; // Serial ATA Active (SCR3: SActive) **RW1** |
95 | 108 | uint32 ci; // Command Issue **RW1** |
diff --git a/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp b/src/add-ons/kernel/busses/scsi/ahci/ahci_port.cpp
index a045771..ed71461 100644
a
|
b
|
AHCIPort::Init1()
|
110 | 110 | // prdt follows after command table |
111 | 111 | |
112 | 112 | // disable transitions to partial or slumber state |
113 | | fRegs->sctl |= 0x300; |
| 113 | fRegs->sctl.ipm |= TRANSITIONS_TO_PARTIAL_SLUMBER_DISABLED; /*TODO Why "|= and not "=" ??*/ |
114 | 114 | |
115 | 115 | // clear IRQ status bits |
116 | 116 | fRegs->is = fRegs->is; |
… |
… |
AHCIPort::Init2()
|
156 | 156 | TRACE("is 0x%08" B_PRIx32 "\n", fRegs->is); |
157 | 157 | TRACE("cmd 0x%08" B_PRIx32 "\n", fRegs->cmd); |
158 | 158 | TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); |
159 | | TRACE("sctl 0x%08" B_PRIx32 "\n", fRegs->sctl); |
| 159 | TRACE("sctl.reserved 0x%04" B_PRIx16 "\n", fRegs->sctl.reserved); |
| 160 | TRACE("sctl.pmp 0x%02" B_PRIx8 "\n", fRegs->sctl.pmp); |
| 161 | TRACE("sctl.spm 0x%02" B_PRIx8 "\n", fRegs->sctl.spm); |
| 162 | TRACE("sctl.ipm 0x%02" B_PRIx8 "\n", fRegs->sctl.ipm); |
| 163 | TRACE("sctl.spd 0x%02" B_PRIx8 "\n", fRegs->sctl.spd); |
| 164 | TRACE("sctl.det 0x%02" B_PRIx8 "\n", fRegs->sctl.det); |
160 | 165 | TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr); |
161 | 166 | TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact); |
162 | 167 | TRACE("tfd 0x%08" B_PRIx32 "\n", fRegs->tfd); |
… |
… |
AHCIPort::ResetDevice()
|
212 | 217 | TRACE("AHCIPort::ResetDevice PORT_CMD_ST set, behaviour undefined\n"); |
213 | 218 | |
214 | 219 | // perform a hard reset |
215 | | fRegs->sctl = (fRegs->sctl & ~0xf) | 1; |
| 220 | fRegs->sctl.det |= INITIALIZATION; //TODO Why "|=" instead of "=" ? |
216 | 221 | FlushPostedWrites(); |
217 | 222 | spin(1100); |
218 | | fRegs->sctl &= ~0xf; |
| 223 | fRegs->sctl.det = NO_INITIALIZATION; |
219 | 224 | FlushPostedWrites(); |
220 | 225 | |
221 | 226 | if (wait_until_set(&fRegs->ssts, 0x1, 100000) < B_OK) { |
… |
… |
AHCIPort::InterruptErrorHandler(uint32 is)
|
364 | 369 | TRACE("AHCIPort::InterruptErrorHandler port %d, fCommandsActive 0x%08" |
365 | 370 | B_PRIx32 ", is 0x%08" B_PRIx32 ", ci 0x%08" B_PRIx32 "\n", fIndex, |
366 | 371 | fCommandsActive, is, ci); |
367 | | |
368 | | TRACE("ssts 0x%08" B_PRIx32 ", sctl 0x%08" B_PRIx32 ", serr 0x%08" |
369 | | B_PRIx32 ", sact 0x%08" B_PRIx32 "\n", |
370 | | fRegs->ssts, fRegs->sctl, fRegs->serr, fRegs->sact); |
| 372 | TRACE("ssts 0x%08" B_PRIx32 "\n", fRegs->ssts); |
| 373 | TRACE("sctl.reserved 0x%04" B_PRIx16 "\n", fRegs->sctl.reserved); |
| 374 | TRACE("sctl.pmp 0x%02" B_PRIx8 "\n", fRegs->sctl.pmp); |
| 375 | TRACE("sctl.spm 0x%02" B_PRIx8 "\n", fRegs->sctl.spm); |
| 376 | TRACE("sctl.ipm 0x%02" B_PRIx8 "\n", fRegs->sctl.ipm); |
| 377 | TRACE("sctl.spd 0x%02" B_PRIx8 "\n", fRegs->sctl.spd); |
| 378 | TRACE("sctl.det 0x%02" B_PRIx8 "\n", fRegs->sctl.det); |
| 379 | TRACE("serr 0x%08" B_PRIx32 "\n", fRegs->serr); |
| 380 | TRACE("sact 0x%08" B_PRIx32 "\n", fRegs->sact); |
371 | 381 | } |
372 | 382 | |
373 | 383 | // read and clear SError |
… |
… |
AHCIPort::InterruptErrorHandler(uint32 is)
|
413 | 423 | } |
414 | 424 | if (is & PORT_INT_PC) { |
415 | 425 | TRACE("Port Connect Change\n"); |
| 426 | /* spec v1.3, §6.2.2.3 Recovery of Unsolicited COMINIT (a COMINIT that is |
| 427 | * not received as a consequence of issuing a COMRESET to the device) */ |
| 428 | |
| 429 | // perform a hard reset |
| 430 | fRegs->sctl.det |= INITIALIZATION; //TODO Why "|=" instead of "=" ? |
| 431 | FlushPostedWrites(); |
| 432 | spin(1100); // specification says you must wait 1ms |
| 433 | fRegs->sctl.det = NO_INITIALIZATION; |
| 434 | FlushPostedWrites(); |
| 435 | |
| 436 | // clear error bits to clear PxSERR.DIAG.X |
| 437 | fRegs->serr = fRegs->serr; |
| 438 | FlushPostedWrites(); |
416 | 439 | // fResetPort = true; |
417 | 440 | } |
418 | 441 | if (is & PORT_INT_UF) { |