aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/scsi_transport_fc.c59
1 files changed, 55 insertions, 4 deletions
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
index 6cd5931d9a54..2a1a99a2ef56 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};
109fc_enum_name_search(port_state, fc_port_state, fc_port_state_names) 110fc_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
215static void fc_shost_remove_rports(void *data);
214static void fc_timeout_deleted_rport(void *data); 216static void fc_timeout_deleted_rport(void *data);
215static void fc_scsi_scan_rport(void *data); 217static void fc_scsi_scan_rport(void *data);
216static void fc_rport_terminate(struct fc_rport *rport); 218static 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 **/
1843static void
1844fc_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
1855restart_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
1821MODULE_AUTHOR("Martin Hicks"); 1872MODULE_AUTHOR("Martin Hicks");
1822MODULE_DESCRIPTION("FC Transport Attributes"); 1873MODULE_DESCRIPTION("FC Transport Attributes");
1823MODULE_LICENSE("GPL"); 1874MODULE_LICENSE("GPL");