aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/pm8001/pm8001_sas.c
diff options
context:
space:
mode:
authorjack wang <jack_wang@usish.com>2009-12-07 04:22:42 -0500
committerJames Bottomley <James.Bottomley@suse.de>2009-12-10 11:00:12 -0500
commit1cc943ae5003e4612a73119cb6fb637a45c2714d (patch)
tree07d7c64475aaec5f05eeea86d13d81b27baee3e1 /drivers/scsi/pm8001/pm8001_sas.c
parent9e79e12554d651f586ff2364e69a8e9cd5e9dbcb (diff)
[SCSI] pm8001: enhance error handle for IO patch
Enhance error handle for IO patch, when the port is down, fast return phy down for task. Signed-off-by: Jack Wang <jack_wang@usish.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_sas.c')
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c49
1 files changed, 48 insertions, 1 deletions
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 1f767a0e727a..49721c886c26 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -329,6 +329,23 @@ int pm8001_slave_configure(struct scsi_device *sdev)
329 } 329 }
330 return 0; 330 return 0;
331} 331}
332 /* Find the local port id that's attached to this device */
333static int sas_find_local_port_id(struct domain_device *dev)
334{
335 struct domain_device *pdev = dev->parent;
336
337 /* Directly attached device */
338 if (!pdev)
339 return dev->port->id;
340 while (pdev) {
341 struct domain_device *pdev_p = pdev->parent;
342 if (!pdev_p)
343 return pdev->port->id;
344 pdev = pdev->parent;
345 }
346 return 0;
347}
348
332/** 349/**
333 * pm8001_task_exec - queue the task(ssp, smp && ata) to the hardware. 350 * pm8001_task_exec - queue the task(ssp, smp && ata) to the hardware.
334 * @task: the task to be execute. 351 * @task: the task to be execute.
@@ -346,11 +363,12 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
346 struct domain_device *dev = task->dev; 363 struct domain_device *dev = task->dev;
347 struct pm8001_hba_info *pm8001_ha; 364 struct pm8001_hba_info *pm8001_ha;
348 struct pm8001_device *pm8001_dev; 365 struct pm8001_device *pm8001_dev;
366 struct pm8001_port *port = NULL;
349 struct sas_task *t = task; 367 struct sas_task *t = task;
350 struct pm8001_ccb_info *ccb; 368 struct pm8001_ccb_info *ccb;
351 u32 tag = 0xdeadbeef, rc, n_elem = 0; 369 u32 tag = 0xdeadbeef, rc, n_elem = 0;
352 u32 n = num; 370 u32 n = num;
353 unsigned long flags = 0; 371 unsigned long flags = 0, flags_libsas = 0;
354 372
355 if (!dev->port) { 373 if (!dev->port) {
356 struct task_status_struct *tsm = &t->task_status; 374 struct task_status_struct *tsm = &t->task_status;
@@ -379,6 +397,35 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
379 rc = SAS_PHY_DOWN; 397 rc = SAS_PHY_DOWN;
380 goto out_done; 398 goto out_done;
381 } 399 }
400 port = &pm8001_ha->port[sas_find_local_port_id(dev)];
401 if (!port->port_attached) {
402 if (sas_protocol_ata(t->task_proto)) {
403 struct task_status_struct *ts = &t->task_status;
404 ts->resp = SAS_TASK_UNDELIVERED;
405 ts->stat = SAS_PHY_DOWN;
406
407 spin_unlock_irqrestore(&pm8001_ha->lock, flags);
408 spin_unlock_irqrestore(dev->sata_dev.ap->lock,
409 flags_libsas);
410 t->task_done(t);
411 spin_lock_irqsave(dev->sata_dev.ap->lock,
412 flags_libsas);
413 spin_lock_irqsave(&pm8001_ha->lock, flags);
414 if (n > 1)
415 t = list_entry(t->list.next,
416 struct sas_task, list);
417 continue;
418 } else {
419 struct task_status_struct *ts = &t->task_status;
420 ts->resp = SAS_TASK_UNDELIVERED;
421 ts->stat = SAS_PHY_DOWN;
422 t->task_done(t);
423 if (n > 1)
424 t = list_entry(t->list.next,
425 struct sas_task, list);
426 continue;
427 }
428 }
382 rc = pm8001_tag_alloc(pm8001_ha, &tag); 429 rc = pm8001_tag_alloc(pm8001_ha, &tag);
383 if (rc) 430 if (rc)
384 goto err_out; 431 goto err_out;