aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/isci/port.c
diff options
context:
space:
mode:
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)