Commit 095478a6 authored by John Garry's avatar John Garry Committed by Martin K. Petersen
Browse files

scsi: hisi_sas: Use libsas internal abort support

Use the common libsas internal abort functionality.

In addition, this driver has special handling for internal abort timeouts -
specifically whether to reset the controller in that instance, so extend
the API for that.

Timeout is now increased to 20 * Hz from 6 * Hz.

We also retry for failure now, but this should not make a difference.

Link: https://lore.kernel.org/r/1647001432-239276-5-git-send-email-john.garry@huawei.com


Tested-by: default avatarDamien Le Moal <damien.lemoal@opensource.wdc.com>
Acked-by: default avatarJack Wang <jinpu.wang@ionos.com>
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent 2cbbf489
Loading
Loading
Loading
Loading
+1 −7
Original line number Diff line number Diff line
@@ -133,11 +133,6 @@ struct hisi_sas_rst {
	bool done;
};

struct hisi_sas_internal_abort {
	unsigned int flag;
	unsigned int tag;
};

#define HISI_SAS_RST_WORK_INIT(r, c) \
	{	.hisi_hba = hisi_hba, \
		.completion = &c, \
@@ -325,8 +320,7 @@ struct hisi_sas_hw {
	void (*prep_stp)(struct hisi_hba *hisi_hba,
			struct hisi_sas_slot *slot);
	void (*prep_abort)(struct hisi_hba *hisi_hba,
			  struct hisi_sas_slot *slot,
			  int device_id, int abort_flag, int tag_to_abort);
			  struct hisi_sas_slot *slot);
	void (*phys_init)(struct hisi_hba *hisi_hba);
	void (*phy_start)(struct hisi_hba *hisi_hba, int phy_no);
	void (*phy_disable)(struct hisi_hba *hisi_hba, int phy_no);
+155 −298
Original line number Diff line number Diff line
@@ -10,10 +10,6 @@
#define DEV_IS_GONE(dev) \
	((!dev) || (dev->dev_type == SAS_PHY_UNUSED))

static int
hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
			     struct domain_device *device,
			     int abort_flag, int tag, bool rst_to_recover);
static int hisi_sas_softreset_ata_disk(struct domain_device *device);
static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
				void *funcdata);
@@ -21,6 +17,10 @@ static void hisi_sas_release_task(struct hisi_hba *hisi_hba,
				  struct domain_device *device);
static void hisi_sas_dev_gone(struct domain_device *device);

struct hisi_sas_internal_abort_data {
	bool rst_ha_timeout; /* reset the HA for timeout */
};

u8 hisi_sas_get_ata_protocol(struct host_to_dev_fis *fis, int direction)
{
	switch (fis->command) {
@@ -263,11 +263,9 @@ static void hisi_sas_task_prep_ata(struct hisi_hba *hisi_hba,
}

static void hisi_sas_task_prep_abort(struct hisi_hba *hisi_hba,
		struct hisi_sas_internal_abort *abort,
		struct hisi_sas_slot *slot, int device_id)
				     struct hisi_sas_slot *slot)
{
	hisi_hba->hw->prep_abort(hisi_hba, slot,
			device_id, abort->flag, abort->tag);
	hisi_hba->hw->prep_abort(hisi_hba, slot);
}

static void hisi_sas_dma_unmap(struct hisi_hba *hisi_hba,
@@ -397,8 +395,7 @@ static
void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
			   struct hisi_sas_slot *slot,
			   struct hisi_sas_dq *dq,
			   struct hisi_sas_device *sas_dev,
			   struct hisi_sas_internal_abort *abort)
			   struct hisi_sas_device *sas_dev)
{
	struct hisi_sas_cmd_hdr *cmd_hdr_base;
	int dlvry_queue_slot, dlvry_queue;
@@ -439,19 +436,15 @@ void hisi_sas_task_deliver(struct hisi_hba *hisi_hba,
		break;
	case SAS_PROTOCOL_SATA:
	case SAS_PROTOCOL_STP:
	case SAS_PROTOCOL_SATA | SAS_PROTOCOL_STP:
	case SAS_PROTOCOL_STP_ALL:
		hisi_sas_task_prep_ata(hisi_hba, slot);
		break;
	case SAS_PROTOCOL_NONE:
		if (abort) {
			hisi_sas_task_prep_abort(hisi_hba, abort, slot, sas_dev->device_id);
	case SAS_PROTOCOL_INTERNAL_ABORT:
		hisi_sas_task_prep_abort(hisi_hba, slot);
		break;
		}
	fallthrough;
	default:
		dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n",
			task->task_proto);
		break;
		return;
	}

	WRITE_ONCE(slot->ready, 1);
@@ -467,6 +460,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
	struct domain_device *device = task->dev;
	struct asd_sas_port *sas_port = device->port;
	struct hisi_sas_device *sas_dev = device->lldd_dev;
	bool internal_abort = sas_is_internal_abort(task);
	struct scsi_cmnd *scmd = NULL;
	struct hisi_sas_dq *dq = NULL;
	struct hisi_sas_port *port;
@@ -484,7 +478,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
		 * libsas will use dev->port, should
		 * not call task_done for sata
		 */
		if (device->dev_type != SAS_SATA_DEV)
		if (device->dev_type != SAS_SATA_DEV && !internal_abort)
			task->task_done(task);
		return -ECOMM;
	}
@@ -492,6 +486,12 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
	hisi_hba = dev_to_hisi_hba(device);
	dev = hisi_hba->dev;

	switch (task->task_proto) {
	case SAS_PROTOCOL_SSP:
	case SAS_PROTOCOL_SMP:
	case SAS_PROTOCOL_SATA:
	case SAS_PROTOCOL_STP:
	case SAS_PROTOCOL_STP_ALL:
		if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) {
			if (!gfpflags_allow_blocking(gfp_flags))
				return -EINVAL;
@@ -511,6 +511,15 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
			return -ECOMM;
		}

		port = to_hisi_sas_port(sas_port);
		if (!port->port_attached) {
			dev_info(dev, "task prep: %s port%d not attach device\n",
				 dev_is_sata(device) ? "SATA/STP" : "SAS",
				 device->port->id);

				return -ECOMM;
		}

		if (task->uldd_task) {
			struct ata_queued_cmd *qc;

@@ -536,15 +545,26 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)

			dq = &hisi_hba->dq[queue];
		}
		break;
	case SAS_PROTOCOL_INTERNAL_ABORT:
		if (!hisi_hba->hw->prep_abort)
			return TMF_RESP_FUNC_FAILED;

	port = to_hisi_sas_port(sas_port);
	if (port && !port->port_attached) {
		dev_info(dev, "task prep: %s port%d not attach device\n",
			 (dev_is_sata(device)) ?
			 "SATA/STP" : "SAS",
			 device->port->id);
		if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags))
			return -EIO;

		return -ECOMM;
		hisi_hba = dev_to_hisi_hba(device);

		if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
			return -EINVAL;

		port = to_hisi_sas_port(sas_port);
		dq = &hisi_hba->dq[task->abort_task.qid];
		break;
	default:
		dev_err(hisi_hba->dev, "task prep: unknown/unsupported proto (0x%x)\n",
			task->task_proto);
		return -EINVAL;
	}

	rc = hisi_sas_dma_map(hisi_hba, task, &n_elem,
@@ -558,7 +578,7 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
			goto err_out_dma_unmap;
	}

	if (hisi_hba->hw->slot_index_alloc)
	if (!internal_abort && hisi_hba->hw->slot_index_alloc)
		rc = hisi_hba->hw->slot_index_alloc(hisi_hba, device);
	else
		rc = hisi_sas_slot_index_alloc(hisi_hba, scmd);
@@ -573,10 +593,10 @@ static int hisi_sas_queue_command(struct sas_task *task, gfp_t gfp_flags)
	slot->port = port;

	slot->tmf = task->tmf;
	slot->is_internal = task->tmf;
	slot->is_internal = !!task->tmf || internal_abort;

	/* protect task_prep and start_delivery sequence */
	hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, NULL);
	hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev);

	return 0;

@@ -1088,6 +1108,29 @@ static void hisi_sas_dereg_device(struct hisi_hba *hisi_hba,
		hisi_hba->hw->dereg_device(hisi_hba, device);
}

static int
hisi_sas_internal_task_abort_dev(struct hisi_sas_device *sas_dev,
				 bool rst_ha_timeout)
{
	struct hisi_sas_internal_abort_data data = { rst_ha_timeout };
	struct domain_device *device = sas_dev->sas_device;
	struct hisi_hba *hisi_hba = sas_dev->hisi_hba;
	int i, rc;

	for (i = 0; i < hisi_hba->cq_nvecs; i++) {
		struct hisi_sas_cq *cq = &hisi_hba->cq[i];
		const struct cpumask *mask = cq->irq_mask;

		if (mask && !cpumask_intersects(cpu_online_mask, mask))
			continue;
		rc = sas_execute_internal_abort_dev(device, i, &data);
		if (rc)
			return rc;
	}

	return 0;
}

static void hisi_sas_dev_gone(struct domain_device *device)
{
	struct hisi_sas_device *sas_dev = device->lldd_dev;
@@ -1100,8 +1143,7 @@ static void hisi_sas_dev_gone(struct domain_device *device)

	down(&hisi_hba->sem);
	if (!test_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) {
		hisi_sas_internal_task_abort(hisi_hba, device,
					     HISI_SAS_INT_ABT_DEV, 0, true);
		hisi_sas_internal_task_abort_dev(sas_dev, true);

		hisi_sas_dereg_device(hisi_hba, device);

@@ -1216,32 +1258,6 @@ static int hisi_sas_control_phy(struct asd_sas_phy *sas_phy, enum phy_func func,
	return ret;
}

static void hisi_sas_task_done(struct sas_task *task)
{
	del_timer_sync(&task->slow_task->timer);
	complete(&task->slow_task->completion);
}

static void hisi_sas_tmf_timedout(struct timer_list *t)
{
	struct sas_task_slow *slow = from_timer(slow, t, timer);
	struct sas_task *task = slow->task;
	unsigned long flags;
	bool is_completed = true;

	spin_lock_irqsave(&task->task_state_lock, flags);
	if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
		is_completed = false;
	}
	spin_unlock_irqrestore(&task->task_state_lock, flags);

	if (!is_completed)
		complete(&task->slow_task->completion);
}

#define INTERNAL_ABORT_TIMEOUT		(6 * HZ)

static void hisi_sas_fill_ata_reset_cmd(struct ata_device *dev,
		bool reset, int pmp, u8 *fis)
{
@@ -1426,9 +1442,7 @@ static void hisi_sas_terminate_stp_reject(struct hisi_hba *hisi_hba)
		if ((sas_dev->dev_type == SAS_PHY_UNUSED) || !device)
			continue;

		rc = hisi_sas_internal_task_abort(hisi_hba, device,
						  HISI_SAS_INT_ABT_DEV, 0,
						  false);
		rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
		if (rc < 0)
			dev_err(dev, "STP reject: abort dev failed %d\n", rc);
	}
@@ -1536,6 +1550,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba)

static int hisi_sas_abort_task(struct sas_task *task)
{
	struct hisi_sas_internal_abort_data internal_abort_data = { false };
	struct domain_device *device = task->dev;
	struct hisi_sas_device *sas_dev = device->lldd_dev;
	struct hisi_hba *hisi_hba;
@@ -1575,9 +1590,8 @@ static int hisi_sas_abort_task(struct sas_task *task)
		int rc2;

		rc = sas_abort_task(task, tag);
		rc2 = hisi_sas_internal_task_abort(hisi_hba, device,
						   HISI_SAS_INT_ABT_CMD, tag,
						   false);
		rc2 = sas_execute_internal_abort_single(device, tag,
				slot->dlvry_queue, &internal_abort_data);
		if (rc2 < 0) {
			dev_err(dev, "abort task: internal abort (%d)\n", rc2);
			return TMF_RESP_FUNC_FAILED;
@@ -1597,9 +1611,7 @@ static int hisi_sas_abort_task(struct sas_task *task)
	} else if (task->task_proto & SAS_PROTOCOL_SATA ||
		task->task_proto & SAS_PROTOCOL_STP) {
		if (task->dev->dev_type == SAS_SATA_DEV) {
			rc = hisi_sas_internal_task_abort(hisi_hba, device,
							  HISI_SAS_INT_ABT_DEV,
							  0, false);
			rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
			if (rc < 0) {
				dev_err(dev, "abort task: internal abort failed\n");
				goto out;
@@ -1613,9 +1625,9 @@ static int hisi_sas_abort_task(struct sas_task *task)
		u32 tag = slot->idx;
		struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue];

		rc = hisi_sas_internal_task_abort(hisi_hba, device,
						  HISI_SAS_INT_ABT_CMD, tag,
						  false);
		rc = sas_execute_internal_abort_single(device,
						       tag, slot->dlvry_queue,
						       &internal_abort_data);
		if (((rc < 0) || (rc == TMF_RESP_FUNC_FAILED)) &&
					task->lldd_task) {
			/*
@@ -1635,12 +1647,12 @@ static int hisi_sas_abort_task(struct sas_task *task)

static int hisi_sas_abort_task_set(struct domain_device *device, u8 *lun)
{
	struct hisi_sas_device *sas_dev = device->lldd_dev;
	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
	struct device *dev = hisi_hba->dev;
	int rc;

	rc = hisi_sas_internal_task_abort(hisi_hba, device,
					  HISI_SAS_INT_ABT_DEV, 0, false);
	rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
	if (rc < 0) {
		dev_err(dev, "abort task set: internal abort rc=%d\n", rc);
		return TMF_RESP_FUNC_FAILED;
@@ -1713,12 +1725,12 @@ static int hisi_sas_debug_I_T_nexus_reset(struct domain_device *device)

static int hisi_sas_I_T_nexus_reset(struct domain_device *device)
{
	struct hisi_sas_device *sas_dev = device->lldd_dev;
	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
	struct device *dev = hisi_hba->dev;
	int rc;

	rc = hisi_sas_internal_task_abort(hisi_hba, device,
					  HISI_SAS_INT_ABT_DEV, 0, false);
	rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
	if (rc < 0) {
		dev_err(dev, "I_T nexus reset: internal abort (%d)\n", rc);
		return TMF_RESP_FUNC_FAILED;
@@ -1766,8 +1778,7 @@ static int hisi_sas_lu_reset(struct domain_device *device, u8 *lun)
	int rc = TMF_RESP_FUNC_FAILED;

	/* Clear internal IO and then lu reset */
	rc = hisi_sas_internal_task_abort(hisi_hba, device,
					  HISI_SAS_INT_ABT_DEV, 0, false);
	rc = hisi_sas_internal_task_abort_dev(sas_dev, false);
	if (rc < 0) {
		dev_err(dev, "lu_reset: internal abort failed\n");
		goto out;
@@ -1862,114 +1873,20 @@ 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, int device_id,
				  struct hisi_sas_internal_abort *abort,
				  struct sas_task *task,
				  struct hisi_sas_dq *dq)
static bool hisi_sas_internal_abort_timeout(struct sas_task *task,
					    void *data)
{
	struct domain_device *device = task->dev;
	struct hisi_sas_device *sas_dev = device->lldd_dev;
	struct device *dev = hisi_hba->dev;
	struct hisi_sas_port *port;
	struct asd_sas_port *sas_port = device->port;
	struct hisi_sas_slot *slot;
	int slot_idx;

	if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags)))
		return -EINVAL;

	if (!device->port)
		return -1;

	port = to_hisi_sas_port(sas_port);

	/* simply get a slot and send abort command */
	slot_idx = hisi_sas_slot_index_alloc(hisi_hba, NULL);
	if (slot_idx < 0)
		goto err_out;

	slot = &hisi_hba->slot_info[slot_idx];
	slot->n_elem = 0;
	slot->task = task;
	slot->port = port;
	slot->is_internal = true;

	hisi_sas_task_deliver(hisi_hba, slot, dq, sas_dev, abort);

	return 0;

err_out:
	dev_err(dev, "internal abort task prep: failed[%d]!\n", slot_idx);

	return slot_idx;
}

/**
 * _hisi_sas_internal_task_abort -- execute an internal
 * abort command for single IO command or a device
 * @hisi_hba: host controller struct
 * @device: domain device
 * @abort_flag: mode of operation, device or single IO
 * @tag: tag of IO to be aborted (only relevant to single
 *       IO mode)
 * @dq: delivery queue for this internal abort command
 * @rst_to_recover: If rst_to_recover set, queue a controller
 *		    reset if an internal abort times out.
 */
static int
_hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
			      struct domain_device *device, int abort_flag,
			      int tag, struct hisi_sas_dq *dq, bool rst_to_recover)
{
	struct sas_task *task;
	struct hisi_sas_device *sas_dev = device->lldd_dev;
	struct hisi_sas_internal_abort abort = {
		.flag = abort_flag,
		.tag = tag,
	};
	struct device *dev = hisi_hba->dev;
	int res;
	/*
	 * The interface is not realized means this HW don't support internal
	 * abort, or don't need to do internal abort. Then here, we return
	 * TMF_RESP_FUNC_FAILED and let other steps go on, which depends that
	 * the internal abort has been executed and returned CQ.
	 */
	if (!hisi_hba->hw->prep_abort)
		return TMF_RESP_FUNC_FAILED;

	if (test_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags))
		return -EIO;

	task = sas_alloc_slow_task(GFP_KERNEL);
	if (!task)
		return -ENOMEM;

	task->dev = device;
	task->task_proto = SAS_PROTOCOL_NONE;
	task->task_done = hisi_sas_task_done;
	task->slow_task->timer.function = hisi_sas_tmf_timedout;
	task->slow_task->timer.expires = jiffies + INTERNAL_ABORT_TIMEOUT;
	add_timer(&task->slow_task->timer);

	res = hisi_sas_internal_abort_task_exec(hisi_hba, sas_dev->device_id,
						&abort, task, dq);
	if (res) {
		del_timer_sync(&task->slow_task->timer);
		dev_err(dev, "internal task abort: executing internal task failed: %d\n",
			res);
		goto exit;
	}
	wait_for_completion(&task->slow_task->completion);
	res = TMF_RESP_FUNC_FAILED;
	struct hisi_hba *hisi_hba = dev_to_hisi_hba(device);
	struct hisi_sas_internal_abort_data *timeout = data;

	/* Internal abort timed out */
	if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
	if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct)
		queue_work(hisi_hba->wq, &hisi_hba->debugfs_work);

		if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
	if (task->task_state_flags & SAS_TASK_STATE_DONE) {
		pr_err("Internal abort: timeout %016llx\n",
		       SAS_ADDR(device->sas_addr));
	} else {
		struct hisi_sas_slot *slot = task->lldd_task;

		set_bit(HISI_SAS_HW_FAULT_BIT, &hisi_hba->flags);
@@ -1985,80 +1902,19 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
			slot->task = NULL;
		}

			if (rst_to_recover) {
				dev_err(dev, "internal task abort: timeout and not done. Queuing reset.\n");
		if (timeout->rst_ha_timeout) {
			pr_err("Internal abort: timeout and not done %016llx. Queuing reset.\n",
			       SAS_ADDR(device->sas_addr));
			queue_work(hisi_hba->wq, &hisi_hba->rst_work);
		} else {
				dev_err(dev, "internal task abort: timeout and not done.\n");
			}

			res = -EIO;
			goto exit;
		} else
			dev_err(dev, "internal task abort: timeout.\n");
	}

	if (task->task_status.resp == SAS_TASK_COMPLETE &&
		task->task_status.stat == TMF_RESP_FUNC_COMPLETE) {
		res = TMF_RESP_FUNC_COMPLETE;
		goto exit;
	}

	if (task->task_status.resp == SAS_TASK_COMPLETE &&
		task->task_status.stat == TMF_RESP_FUNC_SUCC) {
		res = TMF_RESP_FUNC_SUCC;
		goto exit;
	}

exit:
	dev_dbg(dev, "internal task abort: task to dev %016llx task=%pK resp: 0x%x sts 0x%x\n",
		SAS_ADDR(device->sas_addr), task,
		task->task_status.resp, /* 0 is complete, -1 is undelivered */
		task->task_status.stat);
	sas_free_task(task);

	return res;
			pr_err("Internal abort: timeout and not done %016llx.\n",
			       SAS_ADDR(device->sas_addr));
		}

static int
hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba,
			     struct domain_device *device,
			     int abort_flag, int tag, bool rst_to_recover)
{
	struct hisi_sas_slot *slot;
	struct device *dev = hisi_hba->dev;
	struct hisi_sas_dq *dq;
	int i, rc;

	switch (abort_flag) {
	case HISI_SAS_INT_ABT_CMD:
		slot = &hisi_hba->slot_info[tag];
		dq = &hisi_hba->dq[slot->dlvry_queue];
		return _hisi_sas_internal_task_abort(hisi_hba, device,
						     abort_flag, tag, dq,
						     rst_to_recover);
	case HISI_SAS_INT_ABT_DEV:
		for (i = 0; i < hisi_hba->cq_nvecs; i++) {
			struct hisi_sas_cq *cq = &hisi_hba->cq[i];
			const struct cpumask *mask = cq->irq_mask;

			if (mask && !cpumask_intersects(cpu_online_mask, mask))
				continue;
			dq = &hisi_hba->dq[i];
			rc = _hisi_sas_internal_task_abort(hisi_hba, device,
							   abort_flag, tag,
							   dq, rst_to_recover);
			if (rc)
				return rc;
		}
		break;
	default:
		dev_err(dev, "Unrecognised internal abort flag (%d)\n",
			abort_flag);
		return -EINVAL;
		return true;
	}

	return 0;
	return false;
}

static void hisi_sas_port_formed(struct asd_sas_phy *sas_phy)
@@ -2176,6 +2032,7 @@ static struct sas_domain_function_template hisi_sas_transport_ops = {
	.lldd_port_formed	= hisi_sas_port_formed,
	.lldd_write_gpio	= hisi_sas_write_gpio,
	.lldd_tmf_aborted	= hisi_sas_tmf_aborted,
	.lldd_abort_timeout	= hisi_sas_internal_abort_timeout,
};

void hisi_sas_init_mem(struct hisi_hba *hisi_hba)
+6 −5
Original line number Diff line number Diff line
@@ -2603,14 +2603,15 @@ static void hisi_sas_internal_abort_quirk_timeout(struct timer_list *t)
}

static void prep_abort_v2_hw(struct hisi_hba *hisi_hba,
		struct hisi_sas_slot *slot,
		int device_id, int abort_flag, int tag_to_abort)
			     struct hisi_sas_slot *slot)
{
	struct sas_task *task = slot->task;
	struct sas_internal_abort_task *abort = &task->abort_task;
	struct domain_device *dev = task->dev;
	struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
	struct hisi_sas_port *port = slot->port;
	struct timer_list *timer = &slot->internal_abort_timer;
	struct hisi_sas_device *sas_dev = dev->lldd_dev;

	/* setup the quirk timer */
	timer_setup(timer, hisi_sas_internal_abort_quirk_timeout, 0);
@@ -2622,13 +2623,13 @@ static void prep_abort_v2_hw(struct hisi_hba *hisi_hba,
			       (port->id << CMD_HDR_PORT_OFF) |
			       (dev_is_sata(dev) <<
				CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
			       (abort_flag << CMD_HDR_ABORT_FLAG_OFF));
			       (abort->type << CMD_HDR_ABORT_FLAG_OFF));

	/* dw1 */
	hdr->dw1 = cpu_to_le32(device_id << CMD_HDR_DEV_ID_OFF);
	hdr->dw1 = cpu_to_le32(sas_dev->device_id << CMD_HDR_DEV_ID_OFF);

	/* dw7 */
	hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF);
	hdr->dw7 = cpu_to_le32(abort->tag << CMD_HDR_ABORT_IPTT_OFF);
	hdr->transfer_tags = cpu_to_le32(slot->idx);
}

+9 −9
Original line number Diff line number Diff line
@@ -1452,28 +1452,28 @@ static void prep_ata_v3_hw(struct hisi_hba *hisi_hba,
}

static void prep_abort_v3_hw(struct hisi_hba *hisi_hba,
		struct hisi_sas_slot *slot,
		int device_id, int abort_flag, int tag_to_abort)
			     struct hisi_sas_slot *slot)
{
	struct sas_task *task = slot->task;
	struct sas_internal_abort_task *abort = &task->abort_task;
	struct domain_device *dev = task->dev;
	struct hisi_sas_cmd_hdr *hdr = slot->cmd_hdr;
	struct hisi_sas_port *port = slot->port;
	struct hisi_sas_device *sas_dev = dev->lldd_dev;
	bool sata = dev_is_sata(dev);

	/* dw0 */
	hdr->dw0 = cpu_to_le32((5U << CMD_HDR_CMD_OFF) | /* abort */
			       (port->id << CMD_HDR_PORT_OFF) |
				   (dev_is_sata(dev)
					<< CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
					(abort_flag
					 << CMD_HDR_ABORT_FLAG_OFF));
				(sata << CMD_HDR_ABORT_DEVICE_TYPE_OFF) |
				(abort->type << CMD_HDR_ABORT_FLAG_OFF));

	/* dw1 */
	hdr->dw1 = cpu_to_le32(device_id
	hdr->dw1 = cpu_to_le32(sas_dev->device_id
			<< CMD_HDR_DEV_ID_OFF);

	/* dw7 */
	hdr->dw7 = cpu_to_le32(tag_to_abort << CMD_HDR_ABORT_IPTT_OFF);
	hdr->dw7 = cpu_to_le32(abort->tag << CMD_HDR_ABORT_IPTT_OFF);
	hdr->transfer_tags = cpu_to_le32(slot->idx);
}

+10 −3
Original line number Diff line number Diff line
@@ -943,6 +943,7 @@ static int sas_execute_internal_abort(struct domain_device *device,

		task->abort_task.tag = tag;
		task->abort_task.type = type;
		task->abort_task.qid = qid;

		res = i->dft->lldd_execute_task(task, GFP_KERNEL);
		if (res) {
@@ -957,9 +958,15 @@ static int sas_execute_internal_abort(struct domain_device *device,

		/* Even if the internal abort timed out, return direct. */
		if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
			bool quit = true;

			if (i->dft->lldd_abort_timeout)
				quit = i->dft->lldd_abort_timeout(task, data);
			else
				pr_err("Internal abort: timeout %016llx\n",
				       SAS_ADDR(device->sas_addr));
			res = -EIO;
			if (quit)
				break;
		}

Loading