diff options
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_sas.c')
-rw-r--r-- | drivers/scsi/pm8001/pm8001_sas.c | 57 |
1 files changed, 53 insertions, 4 deletions
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 1f767a0e727a..7f9c83a76390 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 */ | ||
333 | static 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; |
@@ -569,11 +616,11 @@ static int pm8001_dev_found_notify(struct domain_device *dev) | |||
569 | spin_lock_irqsave(&pm8001_ha->lock, flags); | 616 | spin_lock_irqsave(&pm8001_ha->lock, flags); |
570 | 617 | ||
571 | pm8001_device = pm8001_alloc_dev(pm8001_ha); | 618 | pm8001_device = pm8001_alloc_dev(pm8001_ha); |
572 | pm8001_device->sas_device = dev; | ||
573 | if (!pm8001_device) { | 619 | if (!pm8001_device) { |
574 | res = -1; | 620 | res = -1; |
575 | goto found_out; | 621 | goto found_out; |
576 | } | 622 | } |
623 | pm8001_device->sas_device = dev; | ||
577 | dev->lldd_dev = pm8001_device; | 624 | dev->lldd_dev = pm8001_device; |
578 | pm8001_device->dev_type = dev->dev_type; | 625 | pm8001_device->dev_type = dev->dev_type; |
579 | pm8001_device->dcompletion = &completion; | 626 | pm8001_device->dcompletion = &completion; |
@@ -609,7 +656,7 @@ static int pm8001_dev_found_notify(struct domain_device *dev) | |||
609 | wait_for_completion(&completion); | 656 | wait_for_completion(&completion); |
610 | if (dev->dev_type == SAS_END_DEV) | 657 | if (dev->dev_type == SAS_END_DEV) |
611 | msleep(50); | 658 | msleep(50); |
612 | pm8001_ha->flags = PM8001F_RUN_TIME ; | 659 | pm8001_ha->flags |= PM8001F_RUN_TIME ; |
613 | return 0; | 660 | return 0; |
614 | found_out: | 661 | found_out: |
615 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); | 662 | spin_unlock_irqrestore(&pm8001_ha->lock, flags); |
@@ -772,7 +819,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, | |||
772 | task->task_done = pm8001_task_done; | 819 | task->task_done = pm8001_task_done; |
773 | task->timer.data = (unsigned long)task; | 820 | task->timer.data = (unsigned long)task; |
774 | task->timer.function = pm8001_tmf_timedout; | 821 | task->timer.function = pm8001_tmf_timedout; |
775 | task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ; | 822 | task->timer.expires = jiffies + PM8001_TASK_TIMEOUT * HZ; |
776 | add_timer(&task->timer); | 823 | add_timer(&task->timer); |
777 | 824 | ||
778 | res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); | 825 | res = pm8001_tag_alloc(pm8001_ha, &ccb_tag); |
@@ -897,6 +944,8 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev) | |||
897 | 944 | ||
898 | if (dev_is_sata(dev)) { | 945 | if (dev_is_sata(dev)) { |
899 | DECLARE_COMPLETION_ONSTACK(completion_setstate); | 946 | DECLARE_COMPLETION_ONSTACK(completion_setstate); |
947 | if (scsi_is_sas_phy_local(phy)) | ||
948 | return 0; | ||
900 | rc = sas_phy_reset(phy, 1); | 949 | rc = sas_phy_reset(phy, 1); |
901 | msleep(2000); | 950 | msleep(2000); |
902 | rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , | 951 | rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , |