From: Jeff Garzik <jgarzik@pobox.com>
To: Tejun Heo <htejun@gmail.com>
Cc: Albert Lee <albertcc@tw.ibm.com>, linux-ide@vger.kernel.org
Subject: Re: [PATCH 1/2] libata: implement ata_exec_internal()
Date: Sun, 04 Dec 2005 14:21:38 -0500 [thread overview]
Message-ID: <439341C2.5090205@pobox.com> (raw)
In-Reply-To: <4392F78A.2040209@gmail.com>
Tejun Heo wrote:
> Jeff Garzik wrote:
>> Tejun Heo wrote:
>>> This is take #2 of ata_exec_internal(). qc allocation and tf
>>> reading-back have also been moved into ata_exec_internal(). Now all
>>> qc handling is done while properly holding host_set lock removing
>>> above mentioned rare race conditon (the second item).
>>>
>>> Index: work/drivers/scsi/libata-core.c
>>> ===================================================================
>>> --- work.orig/drivers/scsi/libata-core.c 2005-11-29
>>> 22:04:15.000000000 +0900
>>> +++ work/drivers/scsi/libata-core.c 2005-11-29 22:06:20.000000000
>>> +0900
>>> @@ -1047,28 +1047,119 @@ static unsigned int ata_pio_modes(const
>>> return modes;
>>> }
>>>
>>> -static int ata_qc_wait_err(struct ata_queued_cmd *qc,
>>> - struct completion *wait)
>>> +struct ata_exec_internal_arg {
>>> + unsigned int err_mask;
>>> + struct ata_taskfile *tf;
>>> + struct completion *waiting;
>>> +};
>>> +
>>> +int ata_qc_complete_internal(struct ata_queued_cmd *qc, unsigned int
>>> err_mask)
>>> {
>>> - int rc = 0;
>>> + struct ata_exec_internal_arg *arg = qc->complete_data;
>>
>>
>>
>> This is what private_data is for. No need to add 'complete_data'.
>>
>
> Hmmm... As there currently isn't any in-kernel user of qc->private_data,
> its ownership status isn't very clear. However, ap->private_data is
> used by most low-level drivers to store its private data, so I assumed
> that qc->private_data belongs to low-level driver too.
>
> Actually, the m15w workaround I'm maintaining uses qc->private_data to
> store context for qc iteration. This can be substitued easily but I
> think it would be nice / more consistent to reserve private_data fields
> for low-level drivers.
qc->private_data is for the creator/owner of the ata_queued_cmd, not for
low-level drivers.
>>> + struct completion *waiting = arg->waiting;
>>>
>>> - if (wait_for_completion_timeout(wait, 30 * HZ) < 1) {
>>> - /* timeout handling */
>>> - unsigned int err_mask = ac_err_mask(ata_chk_status(qc->ap));
>>> -
>>> - if (!err_mask) {
>>> - printk(KERN_WARNING "ata%u: slow completion (cmd %x)\n",
>>> - qc->ap->id, qc->tf.command);
>>> - } else {
>>> - printk(KERN_WARNING "ata%u: qc timeout (cmd %x)\n",
>>> - qc->ap->id, qc->tf.command);
>>> - rc = -EIO;
>>> - }
>>> + if (!(err_mask & ~AC_ERR_DEV))
>>> + qc->ap->ops->tf_read(qc->ap, arg->tf);
>>> + arg->err_mask = err_mask;
>>> + arg->waiting = NULL;
>>> + complete(waiting);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +/**
>>> + * ata_exec_internal - execute libata internal command
>>> + * @ap: Port to which the command is sent
>>> + * @dev: Device to which the command is sent
>>> + * @tf: Taskfile registers for the command and the result
>>> + * @dma_dir: Data tranfer direction of the command
>>> + * @buf: Data buffer of the command
>>> + * @buflen: Length of data buffer
>>> + *
>>> + * Executes libata internal command with timeout. @tf contains
>>> + * command on entry and result on return. Timeout and error
>>> + * conditions are reported via return value. No recovery action
>>> + * is taken after a command times out. It's caller's duty to
>>> + * clean up after timeout.
>>> + *
>>> + * LOCKING:
>>> + * None. Should be called with kernel context, might sleep.
>>> + */
>>> +
>>> +static unsigned
>>> +ata_exec_internal(struct ata_port *ap, struct ata_device *dev,
>>> + struct ata_taskfile *tf,
>>> + int dma_dir, void *buf, unsigned int buflen)
>>> +{
>>> + u8 command = tf->command;
>>> + struct ata_queued_cmd *qc;
>>> + DECLARE_COMPLETION(wait);
>>> + unsigned long flags;
>>> + struct ata_exec_internal_arg arg;
>>> +
>>> + if (ata_busy_sleep(ap, ATA_TMOUT_INTERNAL_QUICK,
>>> ATA_TMOUT_INTERNAL))
>>> + return AC_ERR_OTHER;
>>
>>
>>
>> NAK. This sort of thing really belongs in the execution engine for
>> each driver. Advanced controllers have zero need for this.
>>
>> Moreover, why are you adding this, anyway? This is a distinct
>> regression from the nice "do everything inside ata_qc_issue" model
>> that's been sprouting.
>>
>
> I was thinking that as these internal commands are used for
> initialization and possibly eh in the future, it would be better to give
> drives longer time to get ready for commands. So, the ata_busy_sleep
> with ATA_TMOUT_INTERNAL_QUICK, ATA_TMOUT_INTERNAL timeouts. Too
> paranoid / unnecessary?
Yes, and it breaks the "use ata_queued_cmd for everything" model.
Polling for BSY, etc. should happen in the time between the call to
ata_qc_issue() and the call to ata_qc_complete().
There are some violations of this model in the SRST and IDENTIFY DEVICE
code, but those need to be eliminated, not expanded :)
>>> + spin_lock_irqsave(&ap->host_set->lock, flags);
>>> +
>>> + qc = ata_qc_new_init(ap, dev);
>>> + BUG_ON(qc == NULL);
>>> +
>>> + qc->tf = *tf;
>>> + qc->dma_dir = dma_dir;
>>> + if (dma_dir != DMA_NONE) {
>>> + ata_sg_init_one(qc, buf, buflen);
>>> + qc->nsect = buflen / ATA_SECT_SIZE;
>>> + printk("dma_dir=%d buflen=%u nsect=%d\n",
>>> + dma_dir, buflen, qc->nsect);
>>> + }
>>> +
>>> + arg.waiting = &wait;
>>> + arg.tf = tf;
>>> + qc->complete_data = &arg;
>>> + qc->complete_fn = ata_qc_complete_internal;
>>> +
>>> + if (ata_qc_issue(qc))
>>> + goto issue_fail;
>>> +
>>> + spin_unlock_irqrestore(&ap->host_set->lock, flags);
>>> +
>>> + if (!wait_for_completion_timeout(&wait, ATA_TMOUT_INTERNAL)) {
>>> + int timedout;
>>> +
>>> + spin_lock_irqsave(&ap->host_set->lock, flags);
>>> +
>>> + /* We're racing with irq here. If we lose, the
>>> + * following test prevents us from completing the qc
>>> + * again. If completion irq occurs after here but
>>> + * before the caller cleans up, it will result in a
>>> + * spurious interrupt. We can live with that.
>>> + */
>>> + timedout = arg.waiting != NULL;
>>> + if (timedout)
>>> + ata_qc_complete(qc, 0);
>>
>>
>>
>> This is not very wise, to pass 'nothing is wrong' to ata_qc_complete()
>> upon timeout.
>>
>
> The problem is that we may or may not complete the command successfully
> due to the following slow completion handling. So, completing with
> AC_ERR_OTHER isn't very correct either. This matters because the tf
> registers are read from the completion callback and the completion
> callback does so only on device errors. The solutions are....
>
> 1. leaving as it is with more comments
> 2. completing with AC_ERR_OTHER but always reading back tf regs in the
> completion callback
>
> I prefer #1, but I'm okay with #2, too.
If it times out, call it an error. Easy enough.
> On a side note, I'm sort of doubtful about slow completion handling in
> ata_exec_internal() and also in eng_timeout(). For example, if some
> kind of electrical / cabling glitch occurs during command execution and
> results in device internal reset, the device's reset status can easily
> be interpreted as successful completion by slow completion handling.
>
> Actually, in the current libata, this can be easily triggered by just
> unplugging and replugging the cable on a busy drive as we don't handle
> those events.
You're welcome to improve the libata error handling code ;-)
Jeff
next prev parent reply other threads:[~2005-12-04 19:22 UTC|newest]
Thread overview: 30+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-11-28 16:42 [PATCH] libata: implement ata_qc_exec_internal() Tejun Heo
2005-11-28 17:48 ` Raz Ben-Jehuda(caro)
2005-11-29 3:08 ` Tejun Heo
2005-11-29 3:09 ` Tejun Heo
2005-11-29 3:12 ` Tejun Heo
2005-11-29 7:41 ` Albert Lee
2005-11-29 13:17 ` [PATCH 1/2] libata: implement ata_exec_internal() Tejun Heo
2005-12-04 1:50 ` Jeff Garzik
2005-12-04 14:04 ` Tejun Heo
2005-12-04 19:21 ` Jeff Garzik [this message]
2005-12-05 8:26 ` [PATCH 1/3] " Tejun Heo
2005-12-05 8:28 ` [PATCH 2/4] libata: use ata_exec_internal() Tejun Heo
2005-12-05 8:30 ` [PATCH 3/4] libata: remove unused functions Tejun Heo
2005-12-05 8:31 ` [PATCH 4/4] libata: remove unused qc->waiting Tejun Heo
2005-12-09 9:33 ` [PATCH 1/2] libata: implement ata_exec_internal() Tejun Heo
2005-12-11 4:23 ` [PATCH 1/4] " Tejun Heo
2005-12-13 4:58 ` Jeff Garzik
2005-12-13 5:06 ` Tejun Heo
2005-12-13 5:18 ` Jeff Garzik
2005-12-13 5:48 ` Tejun Heo
2005-12-13 5:49 ` [PATCH 2/4] libata: use ata_exec_internal() Tejun Heo
2005-12-13 5:50 ` [PATCH 3/4] libata: remove unused functions Tejun Heo
2005-12-13 5:51 ` [PATCH 4/4] libata: remove unused qc->waiting Tejun Heo
2005-12-13 6:34 ` [PATCH 1/4] libata: implement ata_exec_internal() Jeff Garzik
2005-12-14 10:01 ` Albert Lee
2005-12-13 5:22 ` Jeff Garzik
2005-12-11 4:24 ` [PATCH 2/4] libata: use ata_exec_internal() Tejun Heo
2005-12-11 4:25 ` [PATCH 3/4] libata: removed unused functions Tejun Heo
2005-12-11 4:26 ` [PATCH 4/4] libata: remove unused qc->waiting Tejun Heo
2005-11-29 13:19 ` [PATCH 2/2] libata: remove qc->waiting Tejun Heo
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=439341C2.5090205@pobox.com \
--to=jgarzik@pobox.com \
--cc=albertcc@tw.ibm.com \
--cc=htejun@gmail.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).