linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Tejun Heo <htejun@gmail.com>
To: Jeff Garzik <jgarzik@pobox.com>
Cc: albertcc@tw.ibm.com, linux-ide@vger.kernel.org
Subject: Re: [PATCH libata-dev-2.6:upstream 00/02] atapi: packet task vs. intr race fix
Date: Mon, 22 Aug 2005 06:38:24 +0900	[thread overview]
Message-ID: <4308F450.4050402@gmail.com> (raw)
In-Reply-To: <4308F114.9020608@pobox.com>


  Howdy, Jeff.

Jeff Garzik wrote:
> Tejun Heo wrote:
> 
>> Jeff Garzik wrote:
>>
>>> Tejun Heo wrote:
>>>
>>>>
>>>>  Hello, Jeff.
>>>>
>>>> Jeff Garzik wrote:
>>>>
>>>>> Tejun Heo wrote:
>>>>>
>>>>>>  Hello, Jeff and Albert.
>>>>>>
>>>>>>  This patchset fixes the following race.
>>>>>> (port A has ATA device and B ATAPI).
>>>>>>
>>>>>> port B    : ata_issue_prot() (ATAPI_NODATA)
>>>>>> port B    : packet_task scheduled
>>>>>> port A    : ata_issue_prot() (DMA)
>>>>>> intr    : ata_interrupt()
>>>>>> port A    : ata_host_intr -> this is all good & dandy
>>>>>> port B    : ata_host_intr -> finishes ATAPI cmd w/ error (request 
>>>>>> sense)
>>>>>>
>>>>>>  This is where the race is, we're polling for port B's qc, we must 
>>>>>> not
>>>>>> mess with it from interrupt.  Now, port B has dangling packet_task
>>>>>> which will race w/ whatever will run on port B.
>>>>>>
>>>>>>  The problem is that we don't always protect polled ports from
>>>>>> interrupts with ata_qc_set_polling() and for non-DMA ATA commands
>>>>>> there's no way to discern if actually an IRQ has occurred (this
>>>>>> sucks), so we end up finishing the other port's command.
>>>>>>
>>>>>>  This condition occurs quite often if both port A and B are busy.  
>>>>>> The
>>>>>> most common result is assertion failure in atapi_packet_task
>>>>>> (assert(qc->flags & ATA_QCFLAG_ACTIVE)), but depending on timing and
>>>>>> on SMP, weirder things could happen, I think.
>>>>>>
>>>>>>  Note that for ATAPI_DMA, interrupt from the other port won't mess
>>>>>> with a polled command as we can tell that it's not ours with
>>>>>> bmdma_status, but, if spurious interrupt occurs on the port, the
>>>>>> packet_task will go dangling.  That's why ATAPI_DMA also needs
>>>>>> protection.  The baseline is that all polled qc's need to be 
>>>>>> protected
>>>>>> with ata_qc_set_polling() until polling task is done with the 
>>>>>> command.
>>>>>>
>>>>>>
>>>>>> [ Start of patch descriptions ]
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> While this is something to look into, the supplied patches are 
>>>>> definitely not the way we want to go.  We need to follow the state 
>>>>> diagram for the PACKET command protocol.  ATA4 [1] diagrams are a 
>>>>> good thing to read, since they include mention of the behavior of 
>>>>> certain ATAPI devices that can send an interrupt between 
>>>>> taskfile-out and write-cdb steps in the sequence.
>>>>>
>>>>> In patch #2, you're making ata_irq_on() way too heavy.  In patch 
>>>>> #1, calling ata_qc_set_polling() for non-polled commands is a hack.
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>  Have you received patches in the reverse order?  #1 changes 
>>>> ata_irq_on() and #2 adds ata_qc_set_polling().
>>>>
>>>>  Hmmm, only a call to ata_chk_status() is added to ata_irq_on(), 
>>>> which I think is needed regardless of other changes, and 
>>>> ata_wait_idle() is removed.  Does that make the function heavy?
>>>>
>>>>>
>>>>> The better solution is to track the PACKET command protocol state 
>>>>> much more closely, so that the code _knows_ when it should and 
>>>>> shouldn't be getting an interrupt.
>>>>>
>>>>> This is required anyway because, as mentioned in another email, an 
>>>>> ATA device might assert INTRQ for certain events, such as non-data 
>>>>> commands, where the controller is not required to assert the BMDMA 
>>>>> IRQ bit.
>>>>>
>>>>> I _suspect_ that many host controllers cause the BMDMA IRQ bit to 
>>>>> track the ATA INTRQ status precisely, but this theory has not been 
>>>>> validated.
>>>>>
>>>>>     Jeff
>>>>>
>>>>>
>>>>> [1] http://www.t13.org/project/d1153r18-ATA-ATAPI-4.pdf
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>  Without interrupt pending information from BMDMA bit for non-DMA 
>>>> commands (which I don't think we can use for non-DMA cmds as we'll 
>>>> never be sure if all controllers behave that way), the problem is 
>>>> that for many SATA controllers, more than one ports share single 
>>>> interrupt line.   And without interrupt pending bit, shared 
>>>> interrupt means a lot of spurious interrupts making it impossible to 
>>>> know when to expect interrupts.
>>>
>>>
>>>
>>>
>>> Incorrect...  this is why I keep harping on the "ATA host state 
>>> machine."
>>>
>>> You rely on proper implementation to know when to expect interrupts. 
>>> Read the state diagrams, they tell you precisely when an interrupt 
>>> may be expected.  By definition, any other interrupt is probably a 
>>> PCI shared interrupt, or a hardware or software bug.
>>>
>>
>>  I think I'm familiar with ATA host state machine.  I don't think I'm 
>> currently saying things because I don't know about it.  Maybe I'm 
>> missing something here.  Please consider the following scenario.
>>
>> 1. non-DMA command issued.
>> 2. device does something
>> 3. another device sharing the IRQ line raises interrupt
>> 4. D2H FIS received (BSY off, DRDY on, INTR on)
>> 5. interrupt handler kicks in for #3
>> 6. SATA controller raises interrupt
>> 7. SATA handler invoked from #5 checks ATA_STATUS and determines that
>>    completes the command (we don't know if it's our interrupt or not)
>> 8. interrupt handler from #5 returns.
>> 9. interrupt handler for #6.
>> 10. nobody cared.
>>
>>  Did I miss something?
> 
> 
> This gets into interrupt controller hardware, how interrupts are 
> asserted and delivered, and similar not-IDE-specific things.
> 
> If you clear the condition (by checking ATA Status) that caused the 
> interrupt hardware to raise an interrupt, during #5 and #7, then the 
> interrupt condition is cleared in the interrupt controller hardware, and 
> the kernel should not invoke the interrupt handler again.
> 

  Ah... yes right.  Gotta be level interrupt to be shared.

> 
>>  I think the problem is whether or not we're expecting interrupts, 
>> we'll get interrupts that are't ours and we have no way to tell if 
>> they're ours or not.  No?
> 
> 
> You can tell just by following normal interrupt assertion rules, and by 
> the "if it's nor ours it's either somebody else's interrupt, or 
> out-of-spec hardware"
> 
> In addition, (slight tangent)
> * if DMA is active, you can check the DMA status bits to see if you have 
> an interrupt condition to handle
> * if DMA is not active, you can check the AltStatus register, to test 
> the state without actually clearing anything
> 
> Though beware, on rare PATA controllers (old Macs?) the AltStatus 
> register doesn't exist.
> 

  Now I see what you're saying.  We should be able to know/clear 
interrupt by reading ATA_STATUS.  So, not having explicit interrupt 
pending bit can be compensated by following changes in ATA_STATUS (so 
the state machine), right?  Thanks a lot for putting up with my ignorance.

  So, how about a port status bit to tell interrupt handler whether or 
not we are expecting an interrupt currently?  That would solve the race 
from I tried to fix in the first patchset.  If that's okay with you, 
I'll redo all four patches accordingly.

  Again, thanks a lot. :-)

-- 
tejun

  reply	other threads:[~2005-08-21 21:38 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-08-20  9:17 [PATCH libata-dev-2.6:upstream 00/02] atapi: packet task vs. intr race fix Tejun Heo
2005-08-20  9:17 ` [PATCH libata-dev-2.6:upstream 01/02] atapi: update ata_irq_on Tejun Heo
2005-08-20  9:17 ` [PATCH libata-dev-2.6:upstream 02/02] atapi: fix atapi_packet_task vs. ata_host_intr race Tejun Heo
2005-08-21 19:47 ` [PATCH libata-dev-2.6:upstream 00/02] atapi: packet task vs. intr race fix Jeff Garzik
2005-08-21 20:17   ` Tejun Heo
2005-08-21 20:23     ` Jeff Garzik
2005-08-21 20:40       ` Tejun Heo
2005-08-21 21:24         ` Jeff Garzik
2005-08-21 21:38           ` Tejun Heo [this message]
2005-08-21 21:59             ` Jeff Garzik
2005-08-21 23:51               ` Tejun Heo
2005-08-22  0:27                 ` Jeff Garzik
2005-08-22  3:57                   ` Tejun Heo
2005-08-22  4:01                     ` Jeff Garzik
2005-08-22  3:59                   ` [PATCH libata:upstream] fix atapi_packet_task vs. intr race Tejun Heo
2005-08-22  4:15                     ` Jeff Garzik
2005-08-22  5:59                       ` [PATCH libata:upstream] fix atapi_packet_task vs. intr race (take 2) Tejun Heo
2005-08-22  6:54                         ` Jeff Garzik
2005-08-22  7:06                           ` Tejun Heo
2005-08-23  5:06                         ` Jeff Garzik
2005-08-21 20:25     ` [PATCH libata-dev-2.6:upstream 00/02] atapi: packet task vs. intr race fix Jeff Garzik
2005-08-22 14:48     ` Mark Lord

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4308F450.4050402@gmail.com \
    --to=htejun@gmail.com \
    --cc=albertcc@tw.ibm.com \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).