*/
#include <linux/kthread.h>
+#include <linux/firmware.h>
+#include <linux/ctype.h>
#include "sas_internal.h"
flags);
SAS_DPRINTK("%s: task 0x%p aborted from "
"task_queue\n",
- __FUNCTION__, task);
+ __func__, task);
return TASK_IS_ABORTED;
}
}
}
for (i = 0; i < 5; i++) {
- SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task);
+ SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task);
res = si->dft->lldd_abort_task(task);
spin_lock_irqsave(&task->task_state_lock, flags);
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+ SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
task);
return TASK_IS_DONE;
}
if (res == TMF_RESP_FUNC_COMPLETE) {
SAS_DPRINTK("%s: task 0x%p is aborted\n",
- __FUNCTION__, task);
+ __func__, task);
return TASK_IS_ABORTED;
} else if (si->dft->lldd_query_task) {
SAS_DPRINTK("%s: querying task 0x%p\n",
- __FUNCTION__, task);
+ __func__, task);
res = si->dft->lldd_query_task(task);
switch (res) {
case TMF_RESP_FUNC_SUCC:
SAS_DPRINTK("%s: task 0x%p at LU\n",
- __FUNCTION__, task);
+ __func__, task);
return TASK_IS_AT_LU;
case TMF_RESP_FUNC_COMPLETE:
SAS_DPRINTK("%s: task 0x%p not at LU\n",
- __FUNCTION__, task);
+ __func__, task);
return TASK_IS_NOT_AT_LU;
case TMF_RESP_FUNC_FAILED:
SAS_DPRINTK("%s: task 0x%p failed to abort\n",
- __FUNCTION__, task);
+ __func__, task);
return TASK_ABORT_FAILED;
}
}
/* Find the sas_phy that's attached to this device */
-static struct sas_phy *find_local_sas_phy(struct domain_device *dev)
+struct sas_phy *sas_find_local_phy(struct domain_device *dev)
{
struct domain_device *pdev = dev->parent;
struct ex_phy *exphy = NULL;
BUG_ON(!exphy);
return exphy->phy;
}
+EXPORT_SYMBOL_GPL(sas_find_local_phy);
/* Attempt to send a LUN reset message to a device */
int sas_eh_device_reset_handler(struct scsi_cmnd *cmd)
int sas_eh_bus_reset_handler(struct scsi_cmnd *cmd)
{
struct domain_device *dev = cmd_to_domain_dev(cmd);
- struct sas_phy *phy = find_local_sas_phy(dev);
+ struct sas_phy *phy = sas_find_local_phy(dev);
int res;
res = sas_phy_reset(phy, 1);
}
/* Try to reset a device */
-static int try_to_reset_cmd_device(struct Scsi_Host *shost,
- struct scsi_cmnd *cmd)
+static int try_to_reset_cmd_device(struct scsi_cmnd *cmd)
{
int res;
+ struct Scsi_Host *shost = cmd->device->host;
if (!shost->hostt->eh_device_reset_handler)
goto try_bus_reset;
need_reset = task->task_state_flags & SAS_TASK_NEED_DEV_RESET;
spin_unlock_irqrestore(&task->task_state_lock, flags);
+ if (need_reset) {
+ SAS_DPRINTK("%s: task 0x%p requests reset\n",
+ __func__, task);
+ goto reset;
+ }
+
SAS_DPRINTK("trying to find task 0x%p\n", task);
res = sas_scsi_find_task(task);
switch (res) {
case TASK_IS_DONE:
- SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__,
+ SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
task);
sas_eh_finish_cmd(cmd);
- if (need_reset)
- try_to_reset_cmd_device(shost, cmd);
continue;
case TASK_IS_ABORTED:
SAS_DPRINTK("%s: task 0x%p is aborted\n",
- __FUNCTION__, task);
+ __func__, task);
sas_eh_finish_cmd(cmd);
- if (need_reset)
- try_to_reset_cmd_device(shost, cmd);
continue;
case TASK_IS_AT_LU:
SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task);
+ reset:
tmf_resp = sas_recover_lu(task->dev, cmd);
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
SAS_DPRINTK("dev %016llx LU %x is "
SAS_ADDR(task->dev),
cmd->device->lun);
sas_eh_finish_cmd(cmd);
- if (need_reset)
- try_to_reset_cmd_device(shost, cmd);
sas_scsi_clear_queue_lu(work_q, cmd);
goto Again;
}
task);
tmf_resp = sas_recover_I_T(task->dev);
if (tmf_resp == TMF_RESP_FUNC_COMPLETE) {
+ struct domain_device *dev = task->dev;
SAS_DPRINTK("I_T %016llx recovered\n",
SAS_ADDR(task->dev->sas_addr));
sas_eh_finish_cmd(cmd);
- if (need_reset)
- try_to_reset_cmd_device(shost, cmd);
- sas_scsi_clear_queue_I_T(work_q, task->dev);
+ sas_scsi_clear_queue_I_T(work_q, dev);
goto Again;
}
/* Hammer time :-) */
+ try_to_reset_cmd_device(cmd);
if (i->dft->lldd_clear_nexus_port) {
struct asd_sas_port *port = task->dev->port;
SAS_DPRINTK("clearing nexus for port:%d\n",
SAS_DPRINTK("clear nexus port:%d "
"succeeded\n", port->id);
sas_eh_finish_cmd(cmd);
- if (need_reset)
- try_to_reset_cmd_device(shost, cmd);
sas_scsi_clear_queue_port(work_q,
port);
goto Again;
SAS_DPRINTK("clear nexus ha "
"succeeded\n");
sas_eh_finish_cmd(cmd);
- if (need_reset)
- try_to_reset_cmd_device(shost, cmd);
goto clear_q;
}
}
cmd->device->lun);
sas_eh_finish_cmd(cmd);
- if (need_reset)
- try_to_reset_cmd_device(shost, cmd);
goto clear_q;
}
}
return list_empty(work_q);
clear_q:
- SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__);
+ SAS_DPRINTK("--- Exit %s -- clear_q\n", __func__);
list_for_each_entry_safe(cmd, n, work_q, eh_entry)
sas_eh_finish_cmd(cmd);
list_splice_init(&shost->eh_cmd_q, &eh_work_q);
spin_unlock_irqrestore(shost->host_lock, flags);
- SAS_DPRINTK("Enter %s\n", __FUNCTION__);
+ SAS_DPRINTK("Enter %s\n", __func__);
/*
* Deal with commands that still have SAS tasks (i.e. they didn't
* complete via the normal sas_task completion mechanism)
out:
scsi_eh_flush_done_q(&ha->eh_done_q);
- SAS_DPRINTK("--- Exit %s\n", __FUNCTION__);
+ SAS_DPRINTK("--- Exit %s\n", __func__);
return;
}
-enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
+enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd)
{
struct sas_task *task = TO_SAS_TASK(cmd);
unsigned long flags;
if (!task) {
- cmd->timeout_per_command /= 2;
+ cmd->request->timeout /= 2;
SAS_DPRINTK("command 0x%p, task 0x%p, gone: %s\n",
- cmd, task, (cmd->timeout_per_command ?
- "EH_RESET_TIMER" : "EH_NOT_HANDLED"));
- if (!cmd->timeout_per_command)
- return EH_NOT_HANDLED;
- return EH_RESET_TIMER;
+ cmd, task, (cmd->request->timeout ?
+ "BLK_EH_RESET_TIMER" : "BLK_EH_NOT_HANDLED"));
+ if (!cmd->request->timeout)
+ return BLK_EH_NOT_HANDLED;
+ return BLK_EH_RESET_TIMER;
}
spin_lock_irqsave(&task->task_state_lock, flags);
BUG_ON(task->task_state_flags & SAS_TASK_STATE_ABORTED);
if (task->task_state_flags & SAS_TASK_STATE_DONE) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n",
- cmd, task);
- return EH_HANDLED;
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: "
+ "BLK_EH_HANDLED\n", cmd, task);
+ return BLK_EH_HANDLED;
}
if (!(task->task_state_flags & SAS_TASK_AT_INITIATOR)) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
SAS_DPRINTK("command 0x%p, task 0x%p, not at initiator: "
- "EH_RESET_TIMER\n",
+ "BLK_EH_RESET_TIMER\n",
cmd, task);
- return EH_RESET_TIMER;
+ return BLK_EH_RESET_TIMER;
}
task->task_state_flags |= SAS_TASK_STATE_ABORTED;
spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n",
+ SAS_DPRINTK("command 0x%p, task 0x%p, timed out: BLK_EH_NOT_HANDLED\n",
cmd, task);
- return EH_NOT_HANDLED;
+ return BLK_EH_NOT_HANDLED;
}
int sas_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
struct domain_device *dev = sdev_to_domain_dev(sdev);
if (dev_is_sata(dev))
- return ata_scsi_ioctl(sdev, cmd, arg);
+ return ata_sas_scsi_ioctl(dev->sata_dev.ap, sdev, cmd, arg);
return -EINVAL;
}
if (task->task_state_flags & SAS_TASK_STATE_ABORTED ||
task->task_state_flags & SAS_TASK_STATE_DONE) {
spin_unlock_irqrestore(&task->task_state_lock, flags);
- SAS_DPRINTK("%s: Task %p already finished.\n", __FUNCTION__,
+ SAS_DPRINTK("%s: Task %p already finished.\n", __func__,
task);
return 0;
}
return;
}
- scsi_req_abort_cmd(sc);
+ blk_abort_request(sc->request);
scsi_schedule_eh(sc->device->host);
}
return;
}
+static void sas_parse_addr(u8 *sas_addr, const char *p)
+{
+ int i;
+ for (i = 0; i < SAS_ADDR_SIZE; i++) {
+ u8 h, l;
+ if (!*p)
+ break;
+ h = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10;
+ p++;
+ l = isdigit(*p) ? *p-'0' : toupper(*p)-'A'+10;
+ p++;
+ sas_addr[i] = (h<<4) | l;
+ }
+}
+
+#define SAS_STRING_ADDR_SIZE 16
+
+int sas_request_addr(struct Scsi_Host *shost, u8 *addr)
+{
+ int res;
+ const struct firmware *fw;
+
+ res = request_firmware(&fw, "sas_addr", &shost->shost_gendev);
+ if (res)
+ return res;
+
+ if (fw->size < SAS_STRING_ADDR_SIZE) {
+ res = -ENODEV;
+ goto out;
+ }
+
+ sas_parse_addr(addr, fw->data);
+
+out:
+ release_firmware(fw);
+ return res;
+}
+EXPORT_SYMBOL_GPL(sas_request_addr);
+
EXPORT_SYMBOL_GPL(sas_queuecommand);
EXPORT_SYMBOL_GPL(sas_target_alloc);
EXPORT_SYMBOL_GPL(sas_slave_configure);