diff options
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/dpt_i2o.c | 25 | ||||
-rw-r--r-- | drivers/scsi/libata-scsi.c | 5 | ||||
-rw-r--r-- | drivers/scsi/scsi_scan.c | 49 | ||||
-rw-r--r-- | drivers/scsi/scsi_transport_fc.c | 59 |
4 files changed, 115 insertions, 23 deletions
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 418fc7b896ac..6252b9ddc01e 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c | |||
@@ -660,7 +660,12 @@ static int adpt_abort(struct scsi_cmnd * cmd) | |||
660 | msg[2] = 0; | 660 | msg[2] = 0; |
661 | msg[3]= 0; | 661 | msg[3]= 0; |
662 | msg[4] = (u32)cmd; | 662 | msg[4] = (u32)cmd; |
663 | if( (rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER)) != 0){ | 663 | if (pHba->host) |
664 | spin_lock_irq(pHba->host->host_lock); | ||
665 | rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER); | ||
666 | if (pHba->host) | ||
667 | spin_unlock_irq(pHba->host->host_lock); | ||
668 | if (rcode != 0) { | ||
664 | if(rcode == -EOPNOTSUPP ){ | 669 | if(rcode == -EOPNOTSUPP ){ |
665 | printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name); | 670 | printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name); |
666 | return FAILED; | 671 | return FAILED; |
@@ -697,10 +702,15 @@ static int adpt_device_reset(struct scsi_cmnd* cmd) | |||
697 | msg[2] = 0; | 702 | msg[2] = 0; |
698 | msg[3] = 0; | 703 | msg[3] = 0; |
699 | 704 | ||
705 | if (pHba->host) | ||
706 | spin_lock_irq(pHba->host->host_lock); | ||
700 | old_state = d->state; | 707 | old_state = d->state; |
701 | d->state |= DPTI_DEV_RESET; | 708 | d->state |= DPTI_DEV_RESET; |
702 | if( (rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER)) ){ | 709 | rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER); |
703 | d->state = old_state; | 710 | d->state = old_state; |
711 | if (pHba->host) | ||
712 | spin_unlock_irq(pHba->host->host_lock); | ||
713 | if (rcode != 0) { | ||
704 | if(rcode == -EOPNOTSUPP ){ | 714 | if(rcode == -EOPNOTSUPP ){ |
705 | printk(KERN_INFO"%s: Device reset not supported\n",pHba->name); | 715 | printk(KERN_INFO"%s: Device reset not supported\n",pHba->name); |
706 | return FAILED; | 716 | return FAILED; |
@@ -708,7 +718,6 @@ static int adpt_device_reset(struct scsi_cmnd* cmd) | |||
708 | printk(KERN_INFO"%s: Device reset failed\n",pHba->name); | 718 | printk(KERN_INFO"%s: Device reset failed\n",pHba->name); |
709 | return FAILED; | 719 | return FAILED; |
710 | } else { | 720 | } else { |
711 | d->state = old_state; | ||
712 | printk(KERN_INFO"%s: Device reset successful\n",pHba->name); | 721 | printk(KERN_INFO"%s: Device reset successful\n",pHba->name); |
713 | return SUCCESS; | 722 | return SUCCESS; |
714 | } | 723 | } |
@@ -721,6 +730,7 @@ static int adpt_bus_reset(struct scsi_cmnd* cmd) | |||
721 | { | 730 | { |
722 | adpt_hba* pHba; | 731 | adpt_hba* pHba; |
723 | u32 msg[4]; | 732 | u32 msg[4]; |
733 | u32 rcode; | ||
724 | 734 | ||
725 | pHba = (adpt_hba*)cmd->device->host->hostdata[0]; | 735 | pHba = (adpt_hba*)cmd->device->host->hostdata[0]; |
726 | memset(msg, 0, sizeof(msg)); | 736 | memset(msg, 0, sizeof(msg)); |
@@ -729,7 +739,12 @@ static int adpt_bus_reset(struct scsi_cmnd* cmd) | |||
729 | msg[1] = (I2O_HBA_BUS_RESET<<24|HOST_TID<<12|pHba->channel[cmd->device->channel].tid); | 739 | msg[1] = (I2O_HBA_BUS_RESET<<24|HOST_TID<<12|pHba->channel[cmd->device->channel].tid); |
730 | msg[2] = 0; | 740 | msg[2] = 0; |
731 | msg[3] = 0; | 741 | msg[3] = 0; |
732 | if(adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER) ){ | 742 | if (pHba->host) |
743 | spin_lock_irq(pHba->host->host_lock); | ||
744 | rcode = adpt_i2o_post_wait(pHba, msg,sizeof(msg), FOREVER); | ||
745 | if (pHba->host) | ||
746 | spin_unlock_irq(pHba->host->host_lock); | ||
747 | if (rcode != 0) { | ||
733 | printk(KERN_WARNING"%s: Bus reset failed.\n",pHba->name); | 748 | printk(KERN_WARNING"%s: Bus reset failed.\n",pHba->name); |
734 | return FAILED; | 749 | return FAILED; |
735 | } else { | 750 | } else { |
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c index 72ddba98f8fb..2282c04fee46 100644 --- a/drivers/scsi/libata-scsi.c +++ b/drivers/scsi/libata-scsi.c | |||
@@ -2044,7 +2044,7 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask) | |||
2044 | else { | 2044 | else { |
2045 | u8 *scsicmd = cmd->cmnd; | 2045 | u8 *scsicmd = cmd->cmnd; |
2046 | 2046 | ||
2047 | if (scsicmd[0] == INQUIRY) { | 2047 | if ((scsicmd[0] == INQUIRY) && ((scsicmd[1] & 0x03) == 0)) { |
2048 | u8 *buf = NULL; | 2048 | u8 *buf = NULL; |
2049 | unsigned int buflen; | 2049 | unsigned int buflen; |
2050 | 2050 | ||
@@ -2058,9 +2058,6 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask) | |||
2058 | * device. 2) Ensure response data format / ATAPI information | 2058 | * device. 2) Ensure response data format / ATAPI information |
2059 | * are always correct. | 2059 | * are always correct. |
2060 | */ | 2060 | */ |
2061 | /* FIXME: do we ever override EVPD pages and the like, with | ||
2062 | * this code? | ||
2063 | */ | ||
2064 | if (buf[2] == 0) { | 2061 | if (buf[2] == 0) { |
2065 | buf[2] = 0x5; | 2062 | buf[2] = 0x5; |
2066 | buf[3] = 0x32; | 2063 | buf[3] = 0x32; |
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 950b087e4ca2..05ebb9cef961 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -400,6 +400,36 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
400 | return found_target; | 400 | return found_target; |
401 | } | 401 | } |
402 | 402 | ||
403 | struct work_queue_wrapper { | ||
404 | struct work_struct work; | ||
405 | struct scsi_target *starget; | ||
406 | }; | ||
407 | |||
408 | static void scsi_target_reap_work(void *data) { | ||
409 | struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data; | ||
410 | struct scsi_target *starget = wqw->starget; | ||
411 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | ||
412 | unsigned long flags; | ||
413 | |||
414 | kfree(wqw); | ||
415 | |||
416 | spin_lock_irqsave(shost->host_lock, flags); | ||
417 | |||
418 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | ||
419 | list_del_init(&starget->siblings); | ||
420 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
421 | transport_remove_device(&starget->dev); | ||
422 | device_del(&starget->dev); | ||
423 | transport_destroy_device(&starget->dev); | ||
424 | put_device(&starget->dev); | ||
425 | return; | ||
426 | |||
427 | } | ||
428 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
429 | |||
430 | return; | ||
431 | } | ||
432 | |||
403 | /** | 433 | /** |
404 | * scsi_target_reap - check to see if target is in use and destroy if not | 434 | * scsi_target_reap - check to see if target is in use and destroy if not |
405 | * | 435 | * |
@@ -411,19 +441,18 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
411 | */ | 441 | */ |
412 | void scsi_target_reap(struct scsi_target *starget) | 442 | void scsi_target_reap(struct scsi_target *starget) |
413 | { | 443 | { |
414 | struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); | 444 | struct work_queue_wrapper *wqw = |
415 | unsigned long flags; | 445 | kzalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC); |
416 | spin_lock_irqsave(shost->host_lock, flags); | ||
417 | 446 | ||
418 | if (--starget->reap_ref == 0 && list_empty(&starget->devices)) { | 447 | if (!wqw) { |
419 | list_del_init(&starget->siblings); | 448 | starget_printk(KERN_ERR, starget, |
420 | spin_unlock_irqrestore(shost->host_lock, flags); | 449 | "Failed to allocate memory in scsi_reap_target()\n"); |
421 | device_del(&starget->dev); | ||
422 | transport_unregister_device(&starget->dev); | ||
423 | put_device(&starget->dev); | ||
424 | return; | 450 | return; |
425 | } | 451 | } |
426 | spin_unlock_irqrestore(shost->host_lock, flags); | 452 | |
453 | INIT_WORK(&wqw->work, scsi_target_reap_work, wqw); | ||
454 | wqw->starget = starget; | ||
455 | schedule_work(&wqw->work); | ||
427 | } | 456 | } |
428 | 457 | ||
429 | /** | 458 | /** |
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index cd95d2ae7b77..685b997306cf 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c | |||
@@ -105,6 +105,7 @@ static struct { | |||
105 | { FC_PORTSTATE_LINKDOWN, "Linkdown" }, | 105 | { FC_PORTSTATE_LINKDOWN, "Linkdown" }, |
106 | { FC_PORTSTATE_ERROR, "Error" }, | 106 | { FC_PORTSTATE_ERROR, "Error" }, |
107 | { FC_PORTSTATE_LOOPBACK, "Loopback" }, | 107 | { FC_PORTSTATE_LOOPBACK, "Loopback" }, |
108 | { FC_PORTSTATE_DELETED, "Deleted" }, | ||
108 | }; | 109 | }; |
109 | fc_enum_name_search(port_state, fc_port_state, fc_port_state_names) | 110 | fc_enum_name_search(port_state, fc_port_state, fc_port_state_names) |
110 | #define FC_PORTSTATE_MAX_NAMELEN 20 | 111 | #define FC_PORTSTATE_MAX_NAMELEN 20 |
@@ -211,6 +212,7 @@ fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names) | |||
211 | #define FC_MGMTSRVR_PORTID 0x00000a | 212 | #define FC_MGMTSRVR_PORTID 0x00000a |
212 | 213 | ||
213 | 214 | ||
215 | static void fc_shost_remove_rports(void *data); | ||
214 | static void fc_timeout_deleted_rport(void *data); | 216 | static void fc_timeout_deleted_rport(void *data); |
215 | static void fc_scsi_scan_rport(void *data); | 217 | static void fc_scsi_scan_rport(void *data); |
216 | static void fc_rport_terminate(struct fc_rport *rport); | 218 | static void fc_rport_terminate(struct fc_rport *rport); |
@@ -318,6 +320,8 @@ static int fc_host_setup(struct transport_container *tc, struct device *dev, | |||
318 | fc_host_next_rport_number(shost) = 0; | 320 | fc_host_next_rport_number(shost) = 0; |
319 | fc_host_next_target_id(shost) = 0; | 321 | fc_host_next_target_id(shost) = 0; |
320 | 322 | ||
323 | fc_host_flags(shost) = 0; | ||
324 | INIT_WORK(&fc_host_rport_del_work(shost), fc_shost_remove_rports, shost); | ||
321 | return 0; | 325 | return 0; |
322 | } | 326 | } |
323 | 327 | ||
@@ -387,6 +391,7 @@ show_fc_rport_##field (struct class_device *cdev, char *buf) \ | |||
387 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | 391 | struct fc_internal *i = to_fc_internal(shost->transportt); \ |
388 | if ((i->f->get_rport_##field) && \ | 392 | if ((i->f->get_rport_##field) && \ |
389 | !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ | 393 | !((rport->port_state == FC_PORTSTATE_BLOCKED) || \ |
394 | (rport->port_state == FC_PORTSTATE_DELETED) || \ | ||
390 | (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ | 395 | (rport->port_state == FC_PORTSTATE_NOTPRESENT))) \ |
391 | i->f->get_rport_##field(rport); \ | 396 | i->f->get_rport_##field(rport); \ |
392 | return snprintf(buf, sz, format_string, cast rport->field); \ | 397 | return snprintf(buf, sz, format_string, cast rport->field); \ |
@@ -402,6 +407,7 @@ store_fc_rport_##field(struct class_device *cdev, const char *buf, \ | |||
402 | struct Scsi_Host *shost = rport_to_shost(rport); \ | 407 | struct Scsi_Host *shost = rport_to_shost(rport); \ |
403 | struct fc_internal *i = to_fc_internal(shost->transportt); \ | 408 | struct fc_internal *i = to_fc_internal(shost->transportt); \ |
404 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ | 409 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || \ |
410 | (rport->port_state == FC_PORTSTATE_DELETED) || \ | ||
405 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ | 411 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) \ |
406 | return -EBUSY; \ | 412 | return -EBUSY; \ |
407 | val = simple_strtoul(buf, NULL, 0); \ | 413 | val = simple_strtoul(buf, NULL, 0); \ |
@@ -519,6 +525,7 @@ store_fc_rport_dev_loss_tmo(struct class_device *cdev, const char *buf, | |||
519 | struct Scsi_Host *shost = rport_to_shost(rport); | 525 | struct Scsi_Host *shost = rport_to_shost(rport); |
520 | struct fc_internal *i = to_fc_internal(shost->transportt); | 526 | struct fc_internal *i = to_fc_internal(shost->transportt); |
521 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || | 527 | if ((rport->port_state == FC_PORTSTATE_BLOCKED) || |
528 | (rport->port_state == FC_PORTSTATE_DELETED) || | ||
522 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) | 529 | (rport->port_state == FC_PORTSTATE_NOTPRESENT)) |
523 | return -EBUSY; | 530 | return -EBUSY; |
524 | val = simple_strtoul(buf, NULL, 0); | 531 | val = simple_strtoul(buf, NULL, 0); |
@@ -1769,7 +1776,7 @@ fc_timeout_deleted_rport(void *data) | |||
1769 | rport->maxframe_size = -1; | 1776 | rport->maxframe_size = -1; |
1770 | rport->supported_classes = FC_COS_UNSPECIFIED; | 1777 | rport->supported_classes = FC_COS_UNSPECIFIED; |
1771 | rport->roles = FC_RPORT_ROLE_UNKNOWN; | 1778 | rport->roles = FC_RPORT_ROLE_UNKNOWN; |
1772 | rport->port_state = FC_PORTSTATE_NOTPRESENT; | 1779 | rport->port_state = FC_PORTSTATE_DELETED; |
1773 | 1780 | ||
1774 | /* remove the identifiers that aren't used in the consisting binding */ | 1781 | /* remove the identifiers that aren't used in the consisting binding */ |
1775 | switch (fc_host_tgtid_bind_type(shost)) { | 1782 | switch (fc_host_tgtid_bind_type(shost)) { |
@@ -1789,14 +1796,23 @@ fc_timeout_deleted_rport(void *data) | |||
1789 | break; | 1796 | break; |
1790 | } | 1797 | } |
1791 | 1798 | ||
1792 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1793 | |||
1794 | /* | 1799 | /* |
1795 | * As this only occurs if the remote port (scsi target) | 1800 | * As this only occurs if the remote port (scsi target) |
1796 | * went away and didn't come back - we'll remove | 1801 | * went away and didn't come back - we'll remove |
1797 | * all attached scsi devices. | 1802 | * all attached scsi devices. |
1803 | * | ||
1804 | * We'll schedule the shost work item to perform the actual removal | ||
1805 | * to avoid recursion in the different flush calls if we perform | ||
1806 | * the removal in each target - and there are lots of targets | ||
1807 | * whose timeouts fire at the same time. | ||
1798 | */ | 1808 | */ |
1799 | fc_rport_tgt_remove(rport); | 1809 | |
1810 | if ( !(fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED)) { | ||
1811 | fc_host_flags(shost) |= FC_SHOST_RPORT_DEL_SCHEDULED; | ||
1812 | scsi_queue_work(shost, &fc_host_rport_del_work(shost)); | ||
1813 | } | ||
1814 | |||
1815 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1800 | } | 1816 | } |
1801 | 1817 | ||
1802 | /** | 1818 | /** |
@@ -1818,6 +1834,41 @@ fc_scsi_scan_rport(void *data) | |||
1818 | } | 1834 | } |
1819 | 1835 | ||
1820 | 1836 | ||
1837 | /** | ||
1838 | * fc_shost_remove_rports - called to remove all rports that are marked | ||
1839 | * as in a deleted (not connected) state. | ||
1840 | * | ||
1841 | * @data: shost whose rports are to be looked at | ||
1842 | **/ | ||
1843 | static void | ||
1844 | fc_shost_remove_rports(void *data) | ||
1845 | { | ||
1846 | struct Scsi_Host *shost = (struct Scsi_Host *)data; | ||
1847 | struct fc_rport *rport, *next_rport; | ||
1848 | unsigned long flags; | ||
1849 | |||
1850 | spin_lock_irqsave(shost->host_lock, flags); | ||
1851 | while (fc_host_flags(shost) & FC_SHOST_RPORT_DEL_SCHEDULED) { | ||
1852 | |||
1853 | fc_host_flags(shost) &= ~FC_SHOST_RPORT_DEL_SCHEDULED; | ||
1854 | |||
1855 | restart_search: | ||
1856 | list_for_each_entry_safe(rport, next_rport, | ||
1857 | &fc_host_rport_bindings(shost), peers) { | ||
1858 | if (rport->port_state == FC_PORTSTATE_DELETED) { | ||
1859 | rport->port_state = FC_PORTSTATE_NOTPRESENT; | ||
1860 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1861 | fc_rport_tgt_remove(rport); | ||
1862 | spin_lock_irqsave(shost->host_lock, flags); | ||
1863 | goto restart_search; | ||
1864 | } | ||
1865 | } | ||
1866 | |||
1867 | } | ||
1868 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1869 | } | ||
1870 | |||
1871 | |||
1821 | MODULE_AUTHOR("Martin Hicks"); | 1872 | MODULE_AUTHOR("Martin Hicks"); |
1822 | MODULE_DESCRIPTION("FC Transport Attributes"); | 1873 | MODULE_DESCRIPTION("FC Transport Attributes"); |
1823 | MODULE_LICENSE("GPL"); | 1874 | MODULE_LICENSE("GPL"); |