* [PATCH 1/6] libata-pmp-prep: add @new_class to ata_dev_revalidate()
2006-07-08 5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
@ 2006-07-08 5:51 ` Tejun Heo
2006-07-08 5:51 ` [PATCH 2/6] libata-pmp-prep: make a number of functions global to libata Tejun Heo
` (4 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08 5:51 UTC (permalink / raw)
To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo
Consider newly found class code while revalidating. PMP resetting
always results in valid class code and issuing PMP commands to
ATA/ATAPI device isn't very attractive. Add @new_class to
ata_dev_revalidate() and check class code for revalidation.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 20 +++++++++++++++-----
drivers/scsi/libata-eh.c | 2 +-
include/linux/libata.h | 3 ++-
3 files changed, 18 insertions(+), 7 deletions(-)
34beb969ad3952cf7a1cc77e5b21f3f1b563ee86
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index a887522..f004675 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2115,7 +2115,7 @@ static int ata_dev_set_mode(struct ata_d
return -EIO;
}
- rc = ata_dev_revalidate(dev, 0);
+ rc = ata_dev_revalidate(dev, ATA_DEV_UNKNOWN, 0);
if (rc)
return rc;
@@ -2985,6 +2985,7 @@ static int ata_dev_same_device(struct at
/**
* ata_dev_revalidate - Revalidate ATA device
* @dev: device to revalidate
+ * @new_class: new class code
* @post_reset: is this revalidation after reset?
*
* Re-read IDENTIFY page and make sure @dev is still attached to
@@ -2996,9 +2997,9 @@ static int ata_dev_same_device(struct at
* RETURNS:
* 0 on success, negative errno otherwise
*/
-int ata_dev_revalidate(struct ata_device *dev, int post_reset)
+int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ int post_reset)
{
- unsigned int class = dev->class;
u16 *id = (void *)dev->link->ap->sector_buf;
int rc;
@@ -3007,13 +3008,22 @@ int ata_dev_revalidate(struct ata_device
goto fail;
}
+ if (ata_class_enabled(new_class)) {
+ /* sometimes wrong class is reported, let it retry */
+ if (new_class != ATA_DEV_ATA && new_class != ATA_DEV_ATAPI) {
+ rc = -EIO;
+ goto fail;
+ }
+ } else
+ new_class = dev->class;
+
/* read ID data */
- rc = ata_dev_read_id(dev, &class, post_reset, id);
+ rc = ata_dev_read_id(dev, &new_class, post_reset, id);
if (rc)
goto fail;
/* is the device still there? */
- if (!ata_dev_same_device(dev, class, id)) {
+ if (!ata_dev_same_device(dev, new_class, id)) {
rc = -ENODEV;
goto fail;
}
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 076badd..55d43c1 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -1717,7 +1717,7 @@ static int ata_eh_revalidate_and_attach(
}
ata_eh_about_to_do(link, dev, ATA_EH_REVALIDATE);
- rc = ata_dev_revalidate(dev,
+ rc = ata_dev_revalidate(dev, ehc->classes[dev->devno],
ehc->i.flags & ATA_EHI_DID_RESET);
if (rc)
break;
diff --git a/include/linux/libata.h b/include/linux/libata.h
index b6715c1..d65bb05 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -693,7 +693,8 @@ extern int sata_std_hardreset(struct ata
extern void ata_std_postreset(struct ata_link *link, unsigned int *classes);
extern void sata_std_hp_poll_activate(struct ata_port *ap);
extern int sata_std_hp_poll(struct ata_port *ap);
-extern int ata_dev_revalidate(struct ata_device *dev, int post_reset);
+extern int ata_dev_revalidate(struct ata_device *dev, unsigned int new_class,
+ int post_reset);
extern void ata_port_disable(struct ata_port *);
extern void ata_std_ports(struct ata_ioports *ioaddr);
#ifdef CONFIG_PCI
--
1.3.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 2/6] libata-pmp-prep: make a number of functions global to libata
2006-07-08 5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
2006-07-08 5:51 ` [PATCH 1/6] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
@ 2006-07-08 5:51 ` Tejun Heo
2006-07-08 5:51 ` [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
` (3 subsequent siblings)
5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08 5:51 UTC (permalink / raw)
To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo
Make a number of functions from libata-core.c and libata-eh.c global
to libata (drivers/scsi/libata.h). These will be used by PMP.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 9 ++++-----
drivers/scsi/libata-eh.c | 31 +++++++++++++++----------------
drivers/scsi/libata.h | 19 +++++++++++++++++++
3 files changed, 38 insertions(+), 21 deletions(-)
883d46c043da3fc913dbe979f49c2c19fd29889b
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index f004675..bb12e16 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -69,7 +69,6 @@ static unsigned int ata_dev_init_params(
u16 heads, u16 sectors);
static unsigned int ata_dev_set_xfermode(struct ata_device *dev);
static void ata_dev_xfermask(struct ata_device *dev);
-static int sata_link_init_spd_limit(struct ata_link *link);
static unsigned int ata_unique_id = 1;
static struct workqueue_struct *ata_wq;
@@ -1656,7 +1655,7 @@ void ata_port_probe(struct ata_port *ap)
* LOCKING:
* None.
*/
-static void sata_print_link_status(struct ata_link *link)
+void sata_print_link_status(struct ata_link *link)
{
u32 sstatus, scontrol, tmp;
@@ -2583,7 +2582,7 @@ int sata_link_resume(struct ata_link *li
return sata_link_debounce(link, params);
}
-static void ata_wait_spinup(struct ata_link *link)
+void ata_wait_spinup(struct ata_link *link)
{
struct ata_eh_context *ehc = &link->eh_context;
unsigned long end, secs;
@@ -5354,7 +5353,7 @@ void ata_dev_init(struct ata_device *dev
* LOCKING:
* Kernel thread context (may sleep)
*/
-static void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
+void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp)
{
struct ata_device *dev;
@@ -5387,7 +5386,7 @@ static void ata_link_init(struct ata_por
* RETURNS:
* 0 on success, -errno on failure.
*/
-static int sata_link_init_spd_limit(struct ata_link *link)
+int sata_link_init_spd_limit(struct ata_link *link)
{
u32 scontrol, spd;
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 55d43c1..e6fd54a 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -59,7 +59,6 @@ struct list_head hp_poll_list = LIST_HEA
DECLARE_WORK(hp_poll_work, ata_hp_poll_worker, NULL);
static void __ata_port_freeze(struct ata_port *ap);
-static void ata_eh_finish(struct ata_port *ap);
static void ata_eh_handle_port_suspend(struct ata_port *ap);
static void ata_eh_handle_port_resume(struct ata_port *ap);
@@ -773,7 +772,7 @@ void ata_eh_qc_retry(struct ata_queued_c
* LOCKING:
* None.
*/
-static void ata_eh_detach_dev(struct ata_device *dev)
+void ata_eh_detach_dev(struct ata_device *dev)
{
struct ata_link *link = dev->link;
struct ata_port *ap = link->ap;
@@ -810,8 +809,8 @@ static void ata_eh_detach_dev(struct ata
* LOCKING:
* None.
*/
-static void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
- unsigned int action)
+void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
struct ata_port *ap = link->ap;
unsigned long flags;
@@ -838,8 +837,8 @@ static void ata_eh_about_to_do(struct at
* LOCKING:
* None.
*/
-static void ata_eh_done(struct ata_link *link, struct ata_device *dev,
- unsigned int action)
+void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action)
{
ata_eh_clear_action(link, dev, &link->eh_context.i, action);
}
@@ -1427,7 +1426,7 @@ static void ata_eh_link_autopsy(struct a
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_autopsy(struct ata_port *ap)
+void ata_eh_autopsy(struct ata_port *ap)
{
struct ata_link *link;
@@ -1513,7 +1512,7 @@ static void ata_eh_link_report(struct at
* LOCKING:
* None.
*/
-static void ata_eh_report(struct ata_port *ap)
+void ata_eh_report(struct ata_port *ap)
{
struct ata_link *link;
@@ -1564,9 +1563,9 @@ static int ata_eh_followup_srst_needed(i
return 0;
}
-static int ata_eh_reset(struct ata_link *link, int classify,
- ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
- ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
+int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
{
struct ata_eh_context *ehc = &link->eh_context;
unsigned int *classes = ehc->classes;
@@ -2039,10 +2038,10 @@ static void ata_eh_handle_dev_fail(struc
* RETURNS:
* 0 on success, -errno on failure.
*/
-static int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
- ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
- ata_postreset_fn_t postreset,
- struct ata_link **r_failed_link)
+int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_link)
{
struct ata_link *link;
struct ata_device *dev;
@@ -2196,7 +2195,7 @@ static int ata_eh_recover(struct ata_por
* LOCKING:
* None.
*/
-static void ata_eh_finish(struct ata_port *ap)
+void ata_eh_finish(struct ata_port *ap)
{
int tag;
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index c544d88..e610894 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -54,11 +54,13 @@ extern unsigned int ata_do_simple_cmd(st
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
int post_reset, u16 *id);
extern int ata_dev_configure(struct ata_device *dev, int print_info);
+extern void sata_print_link_status(struct ata_link *link);
extern int sata_down_spd_limit(struct ata_link *link);
extern int sata_set_spd_needed(struct ata_link *link);
extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
extern int ata_set_mode(struct ata_link *link,
struct ata_device **r_failed_dev);
+extern void ata_wait_spinup(struct ata_link *link);
extern void ata_qc_free(struct ata_queued_cmd *qc);
extern void ata_qc_issue(struct ata_queued_cmd *qc);
extern void __ata_qc_complete(struct ata_queued_cmd *qc);
@@ -68,6 +70,8 @@ extern void ata_dev_select(struct ata_po
extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
extern int ata_flush_cache(struct ata_device *dev);
extern void ata_dev_init(struct ata_device *dev);
+extern void ata_link_init(struct ata_port *ap, struct ata_link *link, int pmp);
+extern int sata_link_init_spd_limit(struct ata_link *link);
extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg);
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
@@ -117,6 +121,21 @@ extern enum scsi_eh_timer_return ata_scs
extern void ata_scsi_error(struct Scsi_Host *host);
extern void ata_port_wait_eh(struct ata_port *ap);
extern void ata_qc_schedule_eh(struct ata_queued_cmd *qc);
+extern void ata_eh_detach_dev(struct ata_device *dev);
+extern void ata_eh_about_to_do(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_done(struct ata_link *link, struct ata_device *dev,
+ unsigned int action);
+extern void ata_eh_autopsy(struct ata_port *ap);
+extern void ata_eh_report(struct ata_port *ap);
+extern int ata_eh_reset(struct ata_link *link, int classify,
+ ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
+ ata_reset_fn_t hardreset, ata_postreset_fn_t postreset);
+extern int ata_eh_recover(struct ata_port *ap, ata_prereset_fn_t prereset,
+ ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
+ ata_postreset_fn_t postreset,
+ struct ata_link **r_failed_disk);
+extern void ata_eh_finish(struct ata_port *ap);
extern void ata_hp_poll_activate(struct ata_port *ap);
extern void ata_hp_poll_deactivate(struct ata_port *ap);
--
1.3.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer()
2006-07-08 5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
2006-07-08 5:51 ` [PATCH 1/6] libata-pmp-prep: add @new_class to ata_dev_revalidate() Tejun Heo
2006-07-08 5:51 ` [PATCH 2/6] libata-pmp-prep: make a number of functions global to libata Tejun Heo
@ 2006-07-08 5:51 ` Tejun Heo
2006-07-19 20:32 ` Jeff Garzik
2006-07-08 5:51 ` [PATCH 3/6] libata-pmp-prep: separate out sata_link_hardreset() Tejun Heo
` (2 subsequent siblings)
5 siblings, 1 reply; 9+ messages in thread
From: Tejun Heo @ 2006-07-08 5:51 UTC (permalink / raw)
To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo
Controllers which support PMP have various restrictions on which
combinations of commands are allowed to what number of devices
concurrently. This patch implements ops->qc_defer() which determines
whether a qc can be issued at the moment or should be deferred.
If the function returns ATA_DEFER_LINK, the qc will be deferred until
a qc completes on the link. If ATA_DEFER_PORT, until a qc completes
on any link. The defer conditions are advisory and in general
ATA_DEFER_LINK can be considered as lower priority deferring than
ATA_DEFER_PORT.
ops->qc_defer() replaces fixed ata_scmd_need_defer(). For standard
NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented. ahci and
sata_sil24 are converted to use ata_std_qc_defer().
ops->qc_defer() is heavier than the original mechanism because full qc
is prepped before determining to defer it, but various information is
needed to determine defer conditinos and fully translating a qc is the
only way to supply such information in generic manner.
IMHO, this shouldn't cause any noticeable performance issues as
* for most cases deferring occurs rarely (except for NCQ-aware
cmd-switching PMP)
* translation itself isn't that expensive
* once deferred the command won't be repeated until another command
completes which usually is a very long time cpu-wise.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/ahci.c | 1 +
drivers/scsi/libata-core.c | 32 ++++++++++++++++++++++++++++
drivers/scsi/libata-scsi.c | 50 +++++++++++---------------------------------
drivers/scsi/sata_sil24.c | 1 +
include/linux/libata.h | 6 +++++
5 files changed, 52 insertions(+), 38 deletions(-)
bdc03a79abfa9d30a7cb1c06c6038a0a5eb65095
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 9f2f66a..17b459f 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -242,6 +242,7 @@ static const struct ata_port_operations
.tf_read = ahci_tf_read,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 38ddeff..f9644db 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -3425,6 +3425,37 @@ int ata_check_atapi_dma(struct ata_queue
return rc;
}
+
+/**
+ * ata_std_qc_defer - Check whether a qc needs to be deferred
+ * @qc: ATA command in question
+ *
+ * Non-NCQ commands cannot run with any other command, NCQ or
+ * not. As upper layer only knows the queue depth, we are
+ * responsible for maintaining exclusion. This function checks
+ * whether a new command @qc can be issued.
+ *
+ * LOCKING:
+ * spin_lock_irqsave(host_set lock)
+ *
+ * RETURNS:
+ * ATA_DEFER_* if deferring is needed, 0 otherwise.
+ */
+int ata_std_qc_defer(struct ata_queued_cmd *qc)
+{
+ struct ata_link *link = qc->dev->link;
+
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
+ if (!ata_tag_valid(link->active_tag))
+ return 0;
+ } else {
+ if (!ata_tag_valid(link->active_tag) && !link->sactive)
+ return 0;
+ }
+
+ return ATA_DEFER_LINK;
+}
+
/**
* ata_qc_prep - Prepare taskfile for submission
* @qc: Metadata associated with taskfile to be prepared
@@ -6150,6 +6181,7 @@ EXPORT_SYMBOL_GPL(ata_interrupt);
EXPORT_SYMBOL_GPL(ata_mmio_data_xfer);
EXPORT_SYMBOL_GPL(ata_pio_data_xfer);
EXPORT_SYMBOL_GPL(ata_pio_data_xfer_noirq);
+EXPORT_SYMBOL_GPL(ata_std_qc_defer);
EXPORT_SYMBOL_GPL(ata_qc_prep);
EXPORT_SYMBOL_GPL(ata_noop_qc_prep);
EXPORT_SYMBOL_GPL(ata_bmdma_setup);
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 7e33506..d446a86 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1458,39 +1458,6 @@ static void ata_scsi_qc_complete(struct
}
/**
- * ata_scmd_need_defer - Check whether we need to defer scmd
- * @dev: ATA device to which the command is addressed
- * @is_io: Is the command IO (and thus possibly NCQ)?
- *
- * NCQ and non-NCQ commands cannot run together. As upper layer
- * only knows the queue depth, we are responsible for maintaining
- * exclusion. This function checks whether a new command can be
- * issued to @dev.
- *
- * LOCKING:
- * spin_lock_irqsave(host_set lock)
- *
- * RETURNS:
- * 1 if deferring is needed, 0 otherwise.
- */
-static int ata_scmd_need_defer(struct ata_device *dev, int is_io)
-{
- struct ata_link *link = dev->link;
-
- if (!(dev->flags & ATA_DFLAG_NCQ))
- return 0;
-
- if (is_io) {
- if (!ata_tag_valid(link->active_tag))
- return 0;
- } else {
- if (!ata_tag_valid(link->active_tag) && !link->sactive)
- return 0;
- }
- return 1;
-}
-
-/**
* ata_scsi_translate - Translate then issue SCSI command to ATA device
* @dev: ATA device to which the command is addressed
* @cmd: SCSI command to execute
@@ -1521,15 +1488,13 @@ static int ata_scsi_translate(struct ata
void (*done)(struct scsi_cmnd *),
ata_xlat_func_t xlat_func)
{
+ struct ata_port *ap = dev->link->ap;
struct ata_queued_cmd *qc;
u8 *scsicmd = cmd->cmnd;
- int is_io = xlat_func == ata_scsi_rw_xlat;
+ int rc;
VPRINTK("ENTER\n");
- if (unlikely(ata_scmd_need_defer(dev, is_io)))
- goto defer;
-
qc = ata_scsi_qc_new(dev, cmd, done);
if (!qc)
goto err_mem;
@@ -1557,6 +1522,11 @@ static int ata_scsi_translate(struct ata
if (xlat_func(qc, scsicmd))
goto early_finish;
+ if (ap->ops->qc_defer) {
+ if ((rc = ap->ops->qc_defer(qc)))
+ goto defer;
+ }
+
/* select device, send command to hardware */
ata_qc_issue(qc);
@@ -1578,8 +1548,12 @@ err_mem:
return 0;
defer:
+ ata_qc_free(qc);
DPRINTK("EXIT - defer\n");
- return SCSI_MLQUEUE_DEVICE_BUSY;
+ if (rc == ATA_DEFER_LINK)
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ else
+ return SCSI_MLQUEUE_HOST_BUSY;
}
/**
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index b1ae88d..68a3fc1 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -391,6 +391,7 @@ static const struct ata_port_operations
.tf_read = sil24_tf_read,
+ .qc_defer = ata_std_qc_defer,
.qc_prep = sil24_qc_prep,
.qc_issue = sil24_qc_issue,
diff --git a/include/linux/libata.h b/include/linux/libata.h
index f46b215..8a4adce 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -249,6 +249,10 @@ enum {
/* ering size */
ATA_ERING_SIZE = 32,
+ /* return values for ->qc_defer */
+ ATA_DEFER_LINK = 1,
+ ATA_DEFER_PORT = 2,
+
/* desc_len for ata_eh_info and context */
ATA_EH_DESC_LEN = 80,
@@ -606,6 +610,7 @@ struct ata_port_operations {
void (*data_xfer) (struct ata_device *, unsigned char *, unsigned int, int);
+ int (*qc_defer) (struct ata_queued_cmd *qc);
void (*qc_prep) (struct ata_queued_cmd *qc);
unsigned int (*qc_issue) (struct ata_queued_cmd *qc);
@@ -759,6 +764,7 @@ extern void ata_pio_data_xfer(struct ata
unsigned int buflen, int write_data);
extern void ata_pio_data_xfer_noirq(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data);
+extern int ata_std_qc_defer(struct ata_queued_cmd *qc);
extern void ata_qc_prep(struct ata_queued_cmd *qc);
extern void ata_noop_qc_prep(struct ata_queued_cmd *qc);
extern unsigned int ata_qc_issue_prot(struct ata_queued_cmd *qc);
--
1.3.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* Re: [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer()
2006-07-08 5:51 ` [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
@ 2006-07-19 20:32 ` Jeff Garzik
2006-07-24 6:21 ` Tejun Heo
0 siblings, 1 reply; 9+ messages in thread
From: Jeff Garzik @ 2006-07-19 20:32 UTC (permalink / raw)
To: Tejun Heo; +Cc: alan, lkml, forrest.zhao, linux-ide
Tejun Heo wrote:
> Controllers which support PMP have various restrictions on which
> combinations of commands are allowed to what number of devices
> concurrently. This patch implements ops->qc_defer() which determines
> whether a qc can be issued at the moment or should be deferred.
>
> If the function returns ATA_DEFER_LINK, the qc will be deferred until
> a qc completes on the link. If ATA_DEFER_PORT, until a qc completes
> on any link. The defer conditions are advisory and in general
> ATA_DEFER_LINK can be considered as lower priority deferring than
> ATA_DEFER_PORT.
>
> ops->qc_defer() replaces fixed ata_scmd_need_defer(). For standard
> NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented. ahci and
> sata_sil24 are converted to use ata_std_qc_defer().
>
> ops->qc_defer() is heavier than the original mechanism because full qc
> is prepped before determining to defer it, but various information is
> needed to determine defer conditinos and fully translating a qc is the
> only way to supply such information in generic manner.
>
> IMHO, this shouldn't cause any noticeable performance issues as
>
> * for most cases deferring occurs rarely (except for NCQ-aware
> cmd-switching PMP)
> * translation itself isn't that expensive
> * once deferred the command won't be repeated until another command
> completes which usually is a very long time cpu-wise.
>
> Signed-off-by: Tejun Heo <htejun@gmail.com>
ACK patches 1-4.
For this patch (#5), I would much rather prefer to update ->qc_issue()
or ->qc_prep() to return a DEFER return value. That matches more
closely other APIs in Linux.
Jeff
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer()
2006-07-19 20:32 ` Jeff Garzik
@ 2006-07-24 6:21 ` Tejun Heo
0 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-24 6:21 UTC (permalink / raw)
To: Jeff Garzik; +Cc: alan, lkml, forrest.zhao, linux-ide
Jeff Garzik wrote:
> Tejun Heo wrote:
>> Controllers which support PMP have various restrictions on which
>> combinations of commands are allowed to what number of devices
>> concurrently. This patch implements ops->qc_defer() which determines
>> whether a qc can be issued at the moment or should be deferred.
>>
>> If the function returns ATA_DEFER_LINK, the qc will be deferred until
>> a qc completes on the link. If ATA_DEFER_PORT, until a qc completes
>> on any link. The defer conditions are advisory and in general
>> ATA_DEFER_LINK can be considered as lower priority deferring than
>> ATA_DEFER_PORT.
>>
>> ops->qc_defer() replaces fixed ata_scmd_need_defer(). For standard
>> NCQ/non-NCQ exclusion, ata_std_qc_defer() is implemented. ahci and
>> sata_sil24 are converted to use ata_std_qc_defer().
>>
>> ops->qc_defer() is heavier than the original mechanism because full qc
>> is prepped before determining to defer it, but various information is
>> needed to determine defer conditinos and fully translating a qc is the
>> only way to supply such information in generic manner.
>>
>> IMHO, this shouldn't cause any noticeable performance issues as
>>
>> * for most cases deferring occurs rarely (except for NCQ-aware
>> cmd-switching PMP)
>> * translation itself isn't that expensive
>> * once deferred the command won't be repeated until another command
>> completes which usually is a very long time cpu-wise.
>>
>> Signed-off-by: Tejun Heo <htejun@gmail.com>
>
> ACK patches 1-4.
>
> For this patch (#5), I would much rather prefer to update ->qc_issue()
> or ->qc_prep() to return a DEFER return value. That matches more
> closely other APIs in Linux.
Will do.
--
tejun
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/6] libata-pmp-prep: separate out sata_link_hardreset()
2006-07-08 5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
` (2 preceding siblings ...)
2006-07-08 5:51 ` [PATCH 5/6] libata-pmp-prep: implement ops->qc_defer() Tejun Heo
@ 2006-07-08 5:51 ` Tejun Heo
2006-07-08 5:51 ` [PATCH 6/6] libata-pmp-prep: implement qc_defer helpers Tejun Heo
2006-07-08 5:51 ` [PATCH 4/6] libata-pmp-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08 5:51 UTC (permalink / raw)
To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo
Separate out sata_link_hardreset() from sata_std_hardreset(). This
will be used by PMP.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 57 ++++++++++++++++++++++++++++++++++----------
drivers/scsi/libata.h | 2 ++
2 files changed, 46 insertions(+), 13 deletions(-)
9a955b32a2ec11df498d7e2dc3005a29a554a6e7
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index bb12e16..4d09167 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2719,11 +2719,11 @@ int ata_std_softreset(struct ata_link *l
}
/**
- * sata_std_hardreset - reset host port via SATA phy reset
+ * sata_link_hardreset - reset link via SATA phy reset
* @link: link to reset
- * @class: resulting class of attached device
+ * @timing: timing parameters { interval, duratinon, timeout } in msec
*
- * SATA phy-reset host port using DET bits of SControl register.
+ * SATA phy-reset @link using DET bits of SControl register.
*
* LOCKING:
* Kernel thread context (may sleep)
@@ -2731,12 +2731,10 @@ int ata_std_softreset(struct ata_link *l
* RETURNS:
* 0 on success, -errno otherwise.
*/
-int sata_std_hardreset(struct ata_link *link, unsigned int *class)
+int sata_link_hardreset(struct ata_link *link, const unsigned long *timing)
{
- struct ata_port *ap = link->ap;
- const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
u32 scontrol;
- int rc;
+ int rc = 0;
DPRINTK("ENTER\n");
@@ -2747,24 +2745,24 @@ int sata_std_hardreset(struct ata_link *
* and Sil3124.
*/
if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
- return rc;
+ goto out;
scontrol = (scontrol & 0x0f0) | 0x302;
if ((rc = sata_scr_write(link, SCR_CONTROL, scontrol)))
- return rc;
+ goto out;
sata_set_spd(link);
}
/* issue phy wake/reset */
if ((rc = sata_scr_read(link, SCR_CONTROL, &scontrol)))
- return rc;
+ goto out;
scontrol = (scontrol & 0x0f0) | 0x301;
if ((rc = sata_scr_write_flush(link, SCR_CONTROL, scontrol)))
- return rc;
+ goto out;
/* Couldn't find anything in SATA I/II specs, but AHCI-1.1
* 10.4.2 says at least 1 ms.
@@ -2772,9 +2770,42 @@ int sata_std_hardreset(struct ata_link *
msleep(1);
/* bring phy back */
- sata_link_resume(link, timing);
+ rc = sata_link_resume(link, timing);
+ out:
+ DPRINTK("EXIT, rc=%d\n", rc);
+ return rc;
+}
+
+/**
+ * sata_std_hardreset - reset host port via SATA phy reset
+ * @link: link to reset
+ * @class: resulting class of attached device
+ *
+ * SATA phy-reset host port using DET bits of SControl register,
+ * wait for !BSY and classify the attached device.
+ *
+ * LOCKING:
+ * Kernel thread context (may sleep)
+ *
+ * RETURNS:
+ * 0 on success, -errno otherwise.
+ */
+int sata_std_hardreset(struct ata_link *link, unsigned int *class)
+{
+ const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
+ struct ata_port *ap = link->ap;
+ int rc;
+
+ DPRINTK("ENTER\n");
+
+ /* do hardreset */
+ rc = sata_link_hardreset(link, timing);
+ if (rc) {
+ ata_link_printk(link, KERN_ERR,
+ "COMRESET failed (errno=%d)\n", rc);
+ return rc;
+ }
- /* TODO: phy layer with polling, timeouts, etc. */
if (ata_link_offline(link)) {
*class = ATA_DEV_NONE;
DPRINTK("EXIT, link offline\n");
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
index e610894..7017b9d 100644
--- a/drivers/scsi/libata.h
+++ b/drivers/scsi/libata.h
@@ -55,6 +55,8 @@ extern int ata_dev_read_id(struct ata_de
int post_reset, u16 *id);
extern int ata_dev_configure(struct ata_device *dev, int print_info);
extern void sata_print_link_status(struct ata_link *link);
+extern int sata_link_hardreset(struct ata_link *link,
+ const unsigned long *timing);
extern int sata_down_spd_limit(struct ata_link *link);
extern int sata_set_spd_needed(struct ata_link *link);
extern int ata_down_xfermask_limit(struct ata_device *dev, int force_pio0);
--
1.3.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 6/6] libata-pmp-prep: implement qc_defer helpers
2006-07-08 5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
` (3 preceding siblings ...)
2006-07-08 5:51 ` [PATCH 3/6] libata-pmp-prep: separate out sata_link_hardreset() Tejun Heo
@ 2006-07-08 5:51 ` Tejun Heo
2006-07-08 5:51 ` [PATCH 4/6] libata-pmp-prep: add @is_cmd to ata_tf_to_fis() Tejun Heo
5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08 5:51 UTC (permalink / raw)
To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo
Implement ap->nr_active_links (the number of links with active qcs),
ap->excl_link (pointer to link which can be used by ->qc_defer and is
cleared when a qc with ATA_QCFLAG_CLEAR_EXCL completes), and
ata_link_active().
These can be used by ->qc_defer() to implement proper command
exclusion. This set of helpers seem enough for both sil24 (ATAPI
exclusion needed) and cmd-switching PMP.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/libata-core.c | 21 +++++++++++++++++++--
drivers/scsi/libata-eh.c | 5 +++++
include/linux/libata.h | 8 ++++++++
3 files changed, 32 insertions(+), 2 deletions(-)
e8c076ff470980da565d0c41bd95c9a1538ab561
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index f9644db..346130c 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1004,6 +1004,7 @@ unsigned ata_exec_internal(struct ata_de
struct ata_queued_cmd *qc;
unsigned int tag, preempted_tag;
u32 preempted_sactive, preempted_qc_active;
+ int preempted_nr_active_links;
DECLARE_COMPLETION_ONSTACK(wait);
unsigned long flags;
unsigned int err_mask;
@@ -1042,9 +1043,11 @@ unsigned ata_exec_internal(struct ata_de
preempted_tag = link->active_tag;
preempted_sactive = link->sactive;
preempted_qc_active = ap->qc_active;
+ preempted_nr_active_links = ap->nr_active_links;
link->active_tag = ATA_TAG_POISON;
link->sactive = 0;
ap->qc_active = 0;
+ ap->nr_active_links = 0;
/* prepare & issue qc */
qc->tf = *tf;
@@ -1114,6 +1117,7 @@ unsigned ata_exec_internal(struct ata_de
link->active_tag = preempted_tag;
link->sactive = preempted_sactive;
ap->qc_active = preempted_qc_active;
+ ap->nr_active_links = preempted_nr_active_links;
/* XXX - Some LLDDs (sata_mv) disable port on command failure.
* Until those drivers are fixed, we detect the condition
@@ -4520,10 +4524,18 @@ void __ata_qc_complete(struct ata_queued
ata_sg_clean(qc);
/* command should be marked inactive atomically with qc completion */
- if (qc->tf.protocol == ATA_PROT_NCQ)
+ if (qc->tf.protocol == ATA_PROT_NCQ) {
link->sactive &= ~(1 << qc->tag);
- else
+ if (!link->sactive)
+ ap->nr_active_links--;
+ } else {
link->active_tag = ATA_TAG_POISON;
+ ap->nr_active_links--;
+ }
+
+ /* clear exclusive status */
+ if (unlikely(qc->flags & ATA_QCFLAG_CLEAR_EXCL))
+ ap->excl_link = NULL;
/* atapi: mark qc as inactive to prevent the interrupt handler
* from completing the command twice later, before the error handler
@@ -4694,9 +4706,14 @@ void ata_qc_issue(struct ata_queued_cmd
if (qc->tf.protocol == ATA_PROT_NCQ) {
WARN_ON(link->sactive & (1 << qc->tag));
+
+ if (!link->sactive)
+ ap->nr_active_links++;
link->sactive |= 1 << qc->tag;
} else {
WARN_ON(link->sactive);
+
+ ap->nr_active_links++;
link->active_tag = qc->tag;
}
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index e6fd54a..122226b 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -293,6 +293,7 @@ void ata_scsi_error(struct Scsi_Host *ho
ap->pflags |= ATA_PFLAG_EH_IN_PROGRESS;
ap->pflags &= ~ATA_PFLAG_EH_PENDING;
+ ap->excl_link = NULL; /* don't maintain exclusion over EH */
spin_unlock_irqrestore(ap->lock, flags);
@@ -2225,6 +2226,10 @@ void ata_eh_finish(struct ata_port *ap)
}
}
}
+
+ /* make sure nr_active_links is zero after EH */
+ WARN_ON(ap->nr_active_links);
+ ap->nr_active_links = 0;
}
/**
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 8a4adce..dea1e5f 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -192,6 +192,7 @@ enum {
ATA_QCFLAG_DMAMAP = ATA_QCFLAG_SG | ATA_QCFLAG_SINGLE,
ATA_QCFLAG_IO = (1 << 3), /* standard IO command */
ATA_QCFLAG_RESULT_TF = (1 << 4), /* result TF requested */
+ ATA_QCFLAG_CLEAR_EXCL = (1 << 5), /* clear excl_link on completion */
ATA_QCFLAG_FAILED = (1 << 16), /* cmd failed and is owned by EH */
ATA_QCFLAG_SENSE_VALID = (1 << 17), /* sense data valid */
@@ -549,12 +550,14 @@ struct ata_port {
struct ata_queued_cmd qcmd[ATA_MAX_QUEUE];
unsigned long qc_allocated;
unsigned int qc_active;
+ int nr_active_links; /* #links with active qcs */
struct ata_link link; /* host default link */
struct ata_device __dev1; /* storage for link.device[1] */
int nr_pmp_links; /* nr of available PMP links */
struct ata_link *pmp_link; /* array of PMP links */
+ struct ata_link *excl_link; /* for PMP qc exclusion */
struct ata_host_stats stats;
struct ata_host_set *host_set;
@@ -1022,6 +1025,11 @@ static inline int ata_link_max_devices(c
return 1;
}
+static inline int ata_link_active(struct ata_link *link)
+{
+ return ata_tag_valid(link->active_tag) || link->sactive;
+}
+
static inline struct ata_link *ata_port_first_link(struct ata_port *ap)
{
if (ap->nr_pmp_links)
--
1.3.2
^ permalink raw reply related [flat|nested] 9+ messages in thread* [PATCH 4/6] libata-pmp-prep: add @is_cmd to ata_tf_to_fis()
2006-07-08 5:51 [PATCHSET 2/3] prep for PMP support, take 2 Tejun Heo
` (4 preceding siblings ...)
2006-07-08 5:51 ` [PATCH 6/6] libata-pmp-prep: implement qc_defer helpers Tejun Heo
@ 2006-07-08 5:51 ` Tejun Heo
5 siblings, 0 replies; 9+ messages in thread
From: Tejun Heo @ 2006-07-08 5:51 UTC (permalink / raw)
To: jgarzik, alan, lkml, forrest.zhao, linux-ide; +Cc: Tejun Heo
Add @is_cmd to ata_tf_to_fis(). This controls bit 7 of the second
byte which tells the device whether this H2D FIS is for a command or
not. This cleans up ahci a bit and will be used by PMP.
Signed-off-by: Tejun Heo <htejun@gmail.com>
---
drivers/scsi/ahci.c | 10 ++++------
drivers/scsi/libata-core.c | 14 ++++++++------
drivers/scsi/sata_qstor.c | 2 +-
drivers/scsi/sata_sil24.c | 2 +-
include/linux/libata.h | 3 ++-
5 files changed, 16 insertions(+), 15 deletions(-)
ce524d81b263d170c5c14c90467ac284d5f06252
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index f41db5d..9f2f66a 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -662,8 +662,7 @@ static int ahci_softreset(struct ata_lin
cmd_fis_len | AHCI_CMD_RESET | AHCI_CMD_CLR_BUSY);
tf.ctl |= ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
+ ata_tf_to_fis(&tf, 0, 0, fis);
writel(1, port_mmio + PORT_CMD_ISSUE);
@@ -681,8 +680,7 @@ static int ahci_softreset(struct ata_lin
ahci_fill_cmd_slot(pp, 0, cmd_fis_len);
tf.ctl &= ~ATA_SRST;
- ata_tf_to_fis(&tf, fis, 0);
- fis[1] &= ~(1 << 7); /* turn off Command FIS bit */
+ ata_tf_to_fis(&tf, 0, 0, fis);
writel(1, port_mmio + PORT_CMD_ISSUE);
readl(port_mmio + PORT_CMD_ISSUE); /* flush */
@@ -732,7 +730,7 @@ static int ahci_hardreset(struct ata_lin
/* clear D2H reception area to properly wait for D2H FIS */
ata_tf_init(link->device, &tf);
tf.command = 0xff;
- ata_tf_to_fis(&tf, d2h_fis, 0);
+ ata_tf_to_fis(&tf, 0, 0, d2h_fis);
rc = sata_std_hardreset(link, class);
@@ -825,7 +823,7 @@ static void ahci_qc_prep(struct ata_queu
*/
cmd_tbl = pp->cmd_tbl + qc->tag * AHCI_CMD_TBL_SZ;
- ata_tf_to_fis(&qc->tf, cmd_tbl, 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, cmd_tbl);
if (is_atapi) {
memset(cmd_tbl + AHCI_CMD_TBL_CDB, 0, 32);
memcpy(cmd_tbl + AHCI_CMD_TBL_CDB, qc->cdb, qc->dev->cdb_len);
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 4d09167..38ddeff 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -100,8 +100,9 @@ MODULE_VERSION(DRV_VERSION);
/**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
* @tf: Taskfile to convert
- * @fis: Buffer into which data will output
* @pmp: Port multiplier port
+ * @is_cmd: This FIS is for command
+ * @fis: Buffer into which data will output
*
* Converts a standard ATA taskfile to a Serial ATA
* FIS structure (Register - Host to Device).
@@ -109,12 +110,13 @@ MODULE_VERSION(DRV_VERSION);
* LOCKING:
* Inherited from caller.
*/
-
-void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp)
+void ata_tf_to_fis(const struct ata_taskfile *tf, u8 pmp, int is_cmd, u8 *fis)
{
- fis[0] = 0x27; /* Register - Host to Device FIS */
- fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
- bit 7 indicates Command FIS */
+ fis[0] = 0x27; /* Register - Host to Device FIS */
+ fis[1] = pmp & 0xf; /* Port multiplier number*/
+ if (is_cmd)
+ fis[1] |= (1 << 7); /* bit 7 indicates Command FIS */
+
fis[2] = tf->command;
fis[3] = tf->feature;
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
index e047890..fca2013 100644
--- a/drivers/scsi/sata_qstor.c
+++ b/drivers/scsi/sata_qstor.c
@@ -336,7 +336,7 @@ static void qs_qc_prep(struct ata_queued
buf[28] = dflags;
/* frame information structure (FIS) */
- ata_tf_to_fis(&qc->tf, &buf[32], 0);
+ ata_tf_to_fis(&qc->tf, 0, 1, &buf[32]);
}
static inline void qs_packet_start(struct ata_queued_cmd *qc)
diff --git a/drivers/scsi/sata_sil24.c b/drivers/scsi/sata_sil24.c
index b2b8d13..b1ae88d 100644
--- a/drivers/scsi/sata_sil24.c
+++ b/drivers/scsi/sata_sil24.c
@@ -706,7 +706,7 @@ static void sil24_qc_prep(struct ata_que
}
prb->ctrl = cpu_to_le16(ctrl);
- ata_tf_to_fis(&qc->tf, prb->fis, 0);
+ ata_tf_to_fis(&qc->tf, qc->dev->link->pmp, 1, prb->fis);
if (qc->flags & ATA_QCFLAG_DMAMAP)
sil24_fill_sg(qc, sge);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index d65bb05..f46b215 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -741,7 +741,8 @@ extern u32 ata_wait_register(void __iome
*/
extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf);
extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
-extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp);
+extern void ata_tf_to_fis(const struct ata_taskfile *tf,
+ u8 pmp, int is_cmd, u8 *fis);
extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf);
extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device);
extern void ata_std_dev_select (struct ata_port *ap, unsigned int device);
--
1.3.2
^ permalink raw reply related [flat|nested] 9+ messages in thread