diff options
Diffstat (limited to 'drivers/scsi/isci/port.c')
-rw-r--r-- | drivers/scsi/isci/port.c | 115 |
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 | ||
155 | static 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 */ | ||
172 | void 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 | |||
195 | void 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 | |||
155 | static void isci_port_link_up(struct isci_host *isci_host, | 220 | static 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 | ||
1036 | static 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 | ||
1855 | static 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 | |||
1868 | void scic_sds_port_broadcast_change_received( | 1903 | void 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) |