Re: [PATCH v2 1/8] hisi_sas: add internal abort main code

2016-08-24 Thread Hannes Reinecke
On 08/24/2016 01:05 PM, John Garry wrote:
> Add main code for internal abort functionality.
> 
> The internal abort features allows the host controller
> to abort commands which are still active in the
> controller but have not yet been sent to the slave
> device.
> 
> Typically a command only spends a relatively
> short time in the controller when compared to the
> amount of the time after it is sent to the slave
> device.
> Two modes of internal abort are supported:
> - device
> - individual command
> 
> For device, when the internal abort is issued all
> commands in the host for that device are aborted.
> For a single command, only that command is aborted
> if it is still in the host.
> 
> In HW the internal abort command is executed
> similar to any other sort of command, like SSP.
> 
> Signed-off-by: John Garry 
> ---
>  drivers/scsi/hisi_sas/hisi_sas.h  |   8 ++
>  drivers/scsi/hisi_sas/hisi_sas_main.c | 163 
> ++
>  2 files changed, 171 insertions(+)
> 
Reviewed-by: Hannes Reinecke 

Cheers,

Hannes
-- 
Dr. Hannes ReineckeTeamlead Storage & Networking
h...@suse.de   +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)


Re: [PATCH v2 1/8] hisi_sas: add internal abort main code

2016-08-24 Thread Hannes Reinecke
On 08/24/2016 01:05 PM, John Garry wrote:
> Add main code for internal abort functionality.
> 
> The internal abort features allows the host controller
> to abort commands which are still active in the
> controller but have not yet been sent to the slave
> device.
> 
> Typically a command only spends a relatively
> short time in the controller when compared to the
> amount of the time after it is sent to the slave
> device.
> Two modes of internal abort are supported:
> - device
> - individual command
> 
> For device, when the internal abort is issued all
> commands in the host for that device are aborted.
> For a single command, only that command is aborted
> if it is still in the host.
> 
> In HW the internal abort command is executed
> similar to any other sort of command, like SSP.
> 
> Signed-off-by: John Garry 
> ---
>  drivers/scsi/hisi_sas/hisi_sas.h  |   8 ++
>  drivers/scsi/hisi_sas/hisi_sas_main.c | 163 
> ++
>  2 files changed, 171 insertions(+)
> 
Reviewed-by: Hannes Reinecke 

Cheers,

Hannes
-- 
Dr. Hannes ReineckeTeamlead Storage & Networking
h...@suse.de   +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)


[PATCH v2 1/8] hisi_sas: add internal abort main code

2016-08-24 Thread John Garry
Add main code for internal abort functionality.

The internal abort features allows the host controller
to abort commands which are still active in the
controller but have not yet been sent to the slave
device.

Typically a command only spends a relatively
short time in the controller when compared to the
amount of the time after it is sent to the slave
device.
Two modes of internal abort are supported:
- device
- individual command

For device, when the internal abort is issued all
commands in the host for that device are aborted.
For a single command, only that command is aborted
if it is still in the host.

In HW the internal abort command is executed
similar to any other sort of command, like SSP.

Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h  |   8 ++
 drivers/scsi/hisi_sas/hisi_sas_main.c | 163 ++
 2 files changed, 171 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 4731d32..8311360 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -56,6 +56,11 @@ enum dev_status {
HISI_SAS_DEV_EH,
 };
 
+enum {
+   HISI_SAS_INT_ABT_CMD = 0,
+   HISI_SAS_INT_ABT_DEV = 1,
+};
+
 enum hisi_sas_dev_type {
HISI_SAS_DEV_TYPE_STP = 0,
HISI_SAS_DEV_TYPE_SSP,
@@ -146,6 +151,9 @@ struct hisi_sas_hw {
struct hisi_sas_slot *slot);
int (*prep_stp)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot);
+   int (*prep_abort)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ int device_id, int abort_flag, int tag_to_abort);
int (*slot_complete)(struct hisi_hba *hisi_hba,
 struct hisi_sas_slot *slot, int abort);
void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 18dd5ea..763c6c5 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -17,6 +17,10 @@
 
 static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
u8 *lun, struct hisi_sas_tmf_task *tmf);
+static int
+hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+struct domain_device *device,
+int abort_flag, int tag);
 
 static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
 {
@@ -116,6 +120,14 @@ static int hisi_sas_task_prep_ata(struct hisi_hba 
*hisi_hba,
return hisi_hba->hw->prep_stp(hisi_hba, slot);
 }
 
+static int hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba,
+   struct hisi_sas_slot *slot,
+   int device_id, int abort_flag, int tag_to_abort)
+{
+   return hisi_hba->hw->prep_abort(hisi_hba, slot,
+   device_id, abort_flag, tag_to_abort);
+}
+
 /*
  * This function will issue an abort TMF regardless of whether the
  * task is in the sdev or not. Then it will do the task complete
@@ -954,6 +966,157 @@ static int hisi_sas_query_task(struct sas_task *task)
return rc;
 }
 
+static int
+hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
+ struct sas_task *task, int abort_flag,
+ int task_tag)
+{
+   struct domain_device *device = task->dev;
+   struct hisi_sas_device *sas_dev = device->lldd_dev;
+   struct device *dev = _hba->pdev->dev;
+   struct hisi_sas_port *port;
+   struct hisi_sas_slot *slot;
+   struct hisi_sas_cmd_hdr *cmd_hdr_base;
+   int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+
+   if (!device->port)
+   return -1;
+
+   port = device->port->lldd_port;
+
+   /* simply get a slot and send abort command */
+   rc = hisi_sas_slot_index_alloc(hisi_hba, _idx);
+   if (rc)
+   goto err_out;
+   rc = hisi_hba->hw->get_free_slot(hisi_hba, _queue,
+_queue_slot);
+   if (rc)
+   goto err_out_tag;
+
+   slot = _hba->slot_info[slot_idx];
+   memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+   slot->idx = slot_idx;
+   slot->n_elem = n_elem;
+   slot->dlvry_queue = dlvry_queue;
+   slot->dlvry_queue_slot = dlvry_queue_slot;
+   cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
+   slot->cmd_hdr = _hdr_base[dlvry_queue_slot];
+   slot->task = task;
+   slot->port = port;
+   task->lldd_task = slot;
+
+   memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
+
+   rc = hisi_sas_task_prep_abort(hisi_hba, slot, device_id,
+ abort_flag, task_tag);
+   if (rc)
+   goto err_out_tag;
+
+   /* Port structure is static for the HBA, so
+   *  even if the 

[PATCH v2 1/8] hisi_sas: add internal abort main code

2016-08-24 Thread John Garry
Add main code for internal abort functionality.

The internal abort features allows the host controller
to abort commands which are still active in the
controller but have not yet been sent to the slave
device.

Typically a command only spends a relatively
short time in the controller when compared to the
amount of the time after it is sent to the slave
device.
Two modes of internal abort are supported:
- device
- individual command

For device, when the internal abort is issued all
commands in the host for that device are aborted.
For a single command, only that command is aborted
if it is still in the host.

In HW the internal abort command is executed
similar to any other sort of command, like SSP.

Signed-off-by: John Garry 
---
 drivers/scsi/hisi_sas/hisi_sas.h  |   8 ++
 drivers/scsi/hisi_sas/hisi_sas_main.c | 163 ++
 2 files changed, 171 insertions(+)

diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h
index 4731d32..8311360 100644
--- a/drivers/scsi/hisi_sas/hisi_sas.h
+++ b/drivers/scsi/hisi_sas/hisi_sas.h
@@ -56,6 +56,11 @@ enum dev_status {
HISI_SAS_DEV_EH,
 };
 
+enum {
+   HISI_SAS_INT_ABT_CMD = 0,
+   HISI_SAS_INT_ABT_DEV = 1,
+};
+
 enum hisi_sas_dev_type {
HISI_SAS_DEV_TYPE_STP = 0,
HISI_SAS_DEV_TYPE_SSP,
@@ -146,6 +151,9 @@ struct hisi_sas_hw {
struct hisi_sas_slot *slot);
int (*prep_stp)(struct hisi_hba *hisi_hba,
struct hisi_sas_slot *slot);
+   int (*prep_abort)(struct hisi_hba *hisi_hba,
+ struct hisi_sas_slot *slot,
+ int device_id, int abort_flag, int tag_to_abort);
int (*slot_complete)(struct hisi_hba *hisi_hba,
 struct hisi_sas_slot *slot, int abort);
void (*phy_enable)(struct hisi_hba *hisi_hba, int phy_no);
diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c 
b/drivers/scsi/hisi_sas/hisi_sas_main.c
index 18dd5ea..763c6c5 100644
--- a/drivers/scsi/hisi_sas/hisi_sas_main.c
+++ b/drivers/scsi/hisi_sas/hisi_sas_main.c
@@ -17,6 +17,10 @@
 
 static int hisi_sas_debug_issue_ssp_tmf(struct domain_device *device,
u8 *lun, struct hisi_sas_tmf_task *tmf);
+static int
+hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
+struct domain_device *device,
+int abort_flag, int tag);
 
 static struct hisi_hba *dev_to_hisi_hba(struct domain_device *device)
 {
@@ -116,6 +120,14 @@ static int hisi_sas_task_prep_ata(struct hisi_hba 
*hisi_hba,
return hisi_hba->hw->prep_stp(hisi_hba, slot);
 }
 
+static int hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba,
+   struct hisi_sas_slot *slot,
+   int device_id, int abort_flag, int tag_to_abort)
+{
+   return hisi_hba->hw->prep_abort(hisi_hba, slot,
+   device_id, abort_flag, tag_to_abort);
+}
+
 /*
  * This function will issue an abort TMF regardless of whether the
  * task is in the sdev or not. Then it will do the task complete
@@ -954,6 +966,157 @@ static int hisi_sas_query_task(struct sas_task *task)
return rc;
 }
 
+static int
+hisi_sas_internal_abort_task_exec(struct hisi_hba *hisi_hba, u64 device_id,
+ struct sas_task *task, int abort_flag,
+ int task_tag)
+{
+   struct domain_device *device = task->dev;
+   struct hisi_sas_device *sas_dev = device->lldd_dev;
+   struct device *dev = _hba->pdev->dev;
+   struct hisi_sas_port *port;
+   struct hisi_sas_slot *slot;
+   struct hisi_sas_cmd_hdr *cmd_hdr_base;
+   int dlvry_queue_slot, dlvry_queue, n_elem = 0, rc, slot_idx;
+
+   if (!device->port)
+   return -1;
+
+   port = device->port->lldd_port;
+
+   /* simply get a slot and send abort command */
+   rc = hisi_sas_slot_index_alloc(hisi_hba, _idx);
+   if (rc)
+   goto err_out;
+   rc = hisi_hba->hw->get_free_slot(hisi_hba, _queue,
+_queue_slot);
+   if (rc)
+   goto err_out_tag;
+
+   slot = _hba->slot_info[slot_idx];
+   memset(slot, 0, sizeof(struct hisi_sas_slot));
+
+   slot->idx = slot_idx;
+   slot->n_elem = n_elem;
+   slot->dlvry_queue = dlvry_queue;
+   slot->dlvry_queue_slot = dlvry_queue_slot;
+   cmd_hdr_base = hisi_hba->cmd_hdr[dlvry_queue];
+   slot->cmd_hdr = _hdr_base[dlvry_queue_slot];
+   slot->task = task;
+   slot->port = port;
+   task->lldd_task = slot;
+
+   memset(slot->cmd_hdr, 0, sizeof(struct hisi_sas_cmd_hdr));
+
+   rc = hisi_sas_task_prep_abort(hisi_hba, slot, device_id,
+ abort_flag, task_tag);
+   if (rc)
+   goto err_out_tag;
+
+   /* Port structure is static for the HBA, so
+   *  even if the port is deformed it is