aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/port.c
diff options
context:
space:
mode:
authorJeff Skirvin <jeffrey.d.skirvin@intel.com>2011-06-21 15:16:33 -0400
committerDan Williams <dan.j.williams@intel.com>2011-07-03 07:04:50 -0400
commit61aaff49e20fdb700f1300a49962bc76effc77fc (patch)
treee00556108ba35fe5610673d1f10cde3440e4ed12 /drivers/scsi/isci/port.c
parentff717ab05f0c33f93514eccea6dfe1a15983e1d1 (diff)
isci: filter broadcast change notifications during SMP phy resets
When resetting a sata device in the domain we have seen occasions where libsas prematurely marks a device gone in the time it takes for the device to re-establish the link. This plays badly with software raid arrays. Other libsas drivers have non-uniform delays in their reset handlers to try to cover this condition, but not sufficient to close the hole. Given that a sata device can take many seconds to recover we filter bcns and poll for the device reattach state before notifying libsas that the port needs the domain to be rediscovered. Once this has been proven out at the lldd level we can think about uplevelling this feature to a common implementation in libsas. Signed-off-by: Jeff Skirvin <jeffrey.d.skirvin@intel.com> [ use kzalloc instead of kmem_cache ] Signed-off-by: Dave Jiang <dave.jiang@intel.com> [ use eventq and time macros ] Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/scsi/isci/port.c')
-rw-r--r--drivers/scsi/isci/port.c115
1 files changed, 75 insertions, 40 deletions
diff --git a/drivers/scsi/isci/port.c b/drivers/scsi/isci/port.c
index 74f06f3c0735..2946eee8e702 100644
--- a/drivers/scsi/isci/port.c
+++ b/drivers/scsi/isci/port.c
@@ -152,6 +152,71 @@ static enum sci_status scic_port_get_properties(struct scic_sds_port *port,
152 return SCI_SUCCESS; 152 return SCI_SUCCESS;
153} 153}
154 154
155static void scic_port_bcn_enable(struct scic_sds_port *sci_port)
156{
157 struct scic_sds_phy *sci_phy;
158 u32 val;
159 int i;
160
161 for (i = 0; i < ARRAY_SIZE(sci_port->phy_table); i++) {
162 sci_phy = sci_port->phy_table[i];
163 if (!sci_phy)
164 continue;
165 val = readl(&sci_phy->link_layer_registers->link_layer_control);
166 /* clear the bit by writing 1. */
167 writel(val, &sci_phy->link_layer_registers->link_layer_control);
168 }
169}
170
171/* called under scic_lock to stabilize phy:port associations */
172void isci_port_bcn_enable(struct isci_host *ihost, struct isci_port *iport)
173{
174 int i;
175
176 clear_bit(IPORT_BCN_BLOCKED, &iport->flags);
177 wake_up(&ihost->eventq);
178
179 if (!test_and_clear_bit(IPORT_BCN_PENDING, &iport->flags))
180 return;
181
182 for (i = 0; i < ARRAY_SIZE(iport->sci.phy_table); i++) {
183 struct scic_sds_phy *sci_phy = iport->sci.phy_table[i];
184 struct isci_phy *iphy = sci_phy_to_iphy(sci_phy);
185
186 if (!sci_phy)
187 continue;
188
189 ihost->sas_ha.notify_port_event(&iphy->sas_phy,
190 PORTE_BROADCAST_RCVD);
191 break;
192 }
193}
194
195void isci_port_bc_change_received(struct isci_host *ihost,
196 struct scic_sds_port *sci_port,
197 struct scic_sds_phy *sci_phy)
198{
199 struct isci_phy *iphy = sci_phy_to_iphy(sci_phy);
200 struct isci_port *iport = iphy->isci_port;
201
202 if (iport && test_bit(IPORT_BCN_BLOCKED, &iport->flags)) {
203 dev_dbg(&ihost->pdev->dev,
204 "%s: disabled BCN; isci_phy = %p, sas_phy = %p\n",
205 __func__, iphy, &iphy->sas_phy);
206 set_bit(IPORT_BCN_PENDING, &iport->flags);
207 atomic_inc(&iport->event);
208 wake_up(&ihost->eventq);
209 } else {
210 dev_dbg(&ihost->pdev->dev,
211 "%s: isci_phy = %p, sas_phy = %p\n",
212 __func__, iphy, &iphy->sas_phy);
213
214 ihost->sas_ha.notify_port_event(&iphy->sas_phy,
215 PORTE_BROADCAST_RCVD);
216 }
217 scic_port_bcn_enable(sci_port);
218}
219
155static void isci_port_link_up(struct isci_host *isci_host, 220static void isci_port_link_up(struct isci_host *isci_host,
156 struct scic_sds_port *port, 221 struct scic_sds_port *port,
157 struct scic_sds_phy *phy) 222 struct scic_sds_phy *phy)
@@ -240,13 +305,15 @@ static void isci_port_link_down(struct isci_host *isci_host,
240 if (isci_port) { 305 if (isci_port) {
241 306
242 /* check to see if this is the last phy on this port. */ 307 /* check to see if this is the last phy on this port. */
243 if (isci_phy->sas_phy.port 308 if (isci_phy->sas_phy.port &&
244 && isci_phy->sas_phy.port->num_phys == 1) { 309 isci_phy->sas_phy.port->num_phys == 1) {
245 310 atomic_inc(&isci_port->event);
246 /* change the state for all devices on this port. 311 isci_port_bcn_enable(isci_host, isci_port);
247 * The next task sent to this device will be returned 312
248 * as SAS_TASK_UNDELIVERED, and the scsi mid layer 313 /* change the state for all devices on this port. The
249 * will remove the target 314 * next task sent to this device will be returned as
315 * SAS_TASK_UNDELIVERED, and the scsi mid layer will
316 * remove the target
250 */ 317 */
251 list_for_each_entry(isci_device, 318 list_for_each_entry(isci_device,
252 &isci_port->remote_dev_list, 319 &isci_port->remote_dev_list,
@@ -1033,26 +1100,6 @@ enum sas_linkrate scic_sds_port_get_max_allowed_speed(
1033 return max_allowed_speed; 1100 return max_allowed_speed;
1034} 1101}
1035 1102
1036static void scic_port_enable_broadcast_change_notification(struct scic_sds_port *port)
1037{
1038 struct scic_sds_phy *phy;
1039 u32 register_value;
1040 u8 index;
1041
1042 /* Loop through all of the phys to enable BCN. */
1043 for (index = 0; index < SCI_MAX_PHYS; index++) {
1044 phy = port->phy_table[index];
1045 if (phy != NULL) {
1046 register_value =
1047 readl(&phy->link_layer_registers->link_layer_control);
1048
1049 /* clear the bit by writing 1. */
1050 writel(register_value,
1051 &phy->link_layer_registers->link_layer_control);
1052 }
1053 }
1054}
1055
1056/** 1103/**
1057 * 1104 *
1058 * @sci_port: This is the struct scic_sds_port object to suspend. 1105 * @sci_port: This is the struct scic_sds_port object to suspend.
@@ -1838,6 +1885,7 @@ void isci_port_init(struct isci_port *iport, struct isci_host *ihost, int index)
1838 init_completion(&iport->start_complete); 1885 init_completion(&iport->start_complete);
1839 iport->isci_host = ihost; 1886 iport->isci_host = ihost;
1840 isci_port_change_state(iport, isci_freed); 1887 isci_port_change_state(iport, isci_freed);
1888 atomic_set(&iport->event, 0);
1841} 1889}
1842 1890
1843/** 1891/**
@@ -1852,19 +1900,6 @@ enum isci_status isci_port_get_state(
1852 return isci_port->status; 1900 return isci_port->status;
1853} 1901}
1854 1902
1855static void isci_port_bc_change_received(struct isci_host *ihost,
1856 struct scic_sds_port *sci_port,
1857 struct scic_sds_phy *sci_phy)
1858{
1859 struct isci_phy *iphy = sci_phy_to_iphy(sci_phy);
1860
1861 dev_dbg(&ihost->pdev->dev, "%s: iphy = %p, sas_phy = %p\n",
1862 __func__, iphy, &iphy->sas_phy);
1863
1864 ihost->sas_ha.notify_port_event(&iphy->sas_phy, PORTE_BROADCAST_RCVD);
1865 scic_port_enable_broadcast_change_notification(sci_port);
1866}
1867
1868void scic_sds_port_broadcast_change_received( 1903void scic_sds_port_broadcast_change_received(
1869 struct scic_sds_port *sci_port, 1904 struct scic_sds_port *sci_port,
1870 struct scic_sds_phy *sci_phy) 1905 struct scic_sds_phy *sci_phy)