diff options
author | malahal@us.ibm.com <malahal@us.ibm.com> | 2006-10-04 20:28:37 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2006-11-09 00:27:48 -0500 |
commit | 3f048109d9c4f8bb028ccb0d256ab65eb44f5988 (patch) | |
tree | 4a37dcbda611cf7e67f1dc27bc1843a17ac4c3e2 /drivers/scsi/aic94xx/aic94xx_scb.c | |
parent | 088406bcf66d6c7fd8a5c04c00aa410ae9077403 (diff) |
[SCSI] aic94xx SCSI timeout fix
The patch updates DDB0 in the aic94xx driver itself. It doesn't supply
or use lldd_port_formed field. DDB0 is updated prior to posting
notification to libsas layer.
Signed-off-by: Malahal Naineni <malahal@us.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aic94xx/aic94xx_scb.c')
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_scb.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c index 7ee49b51b724..b15caf1c8fa2 100644 --- a/drivers/scsi/aic94xx/aic94xx_scb.c +++ b/drivers/scsi/aic94xx/aic94xx_scb.c | |||
@@ -168,6 +168,70 @@ static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr) | |||
168 | } | 168 | } |
169 | } | 169 | } |
170 | 170 | ||
171 | static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy) | ||
172 | { | ||
173 | int i; | ||
174 | struct asd_port *free_port = NULL; | ||
175 | struct asd_port *port; | ||
176 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
177 | unsigned long flags; | ||
178 | |||
179 | spin_lock_irqsave(&asd_ha->asd_ports_lock, flags); | ||
180 | if (!phy->asd_port) { | ||
181 | for (i = 0; i < ASD_MAX_PHYS; i++) { | ||
182 | port = &asd_ha->asd_ports[i]; | ||
183 | |||
184 | /* Check for wide port */ | ||
185 | if (port->num_phys > 0 && | ||
186 | memcmp(port->sas_addr, sas_phy->sas_addr, | ||
187 | SAS_ADDR_SIZE) == 0 && | ||
188 | memcmp(port->attached_sas_addr, | ||
189 | sas_phy->attached_sas_addr, | ||
190 | SAS_ADDR_SIZE) == 0) { | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | /* Find a free port */ | ||
195 | if (port->num_phys == 0 && free_port == NULL) { | ||
196 | free_port = port; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | /* Use a free port if this doesn't form a wide port */ | ||
201 | if (i >= ASD_MAX_PHYS) { | ||
202 | port = free_port; | ||
203 | BUG_ON(!port); | ||
204 | memcpy(port->sas_addr, sas_phy->sas_addr, | ||
205 | SAS_ADDR_SIZE); | ||
206 | memcpy(port->attached_sas_addr, | ||
207 | sas_phy->attached_sas_addr, | ||
208 | SAS_ADDR_SIZE); | ||
209 | } | ||
210 | port->num_phys++; | ||
211 | port->phy_mask |= (1U << sas_phy->id); | ||
212 | phy->asd_port = port; | ||
213 | } | ||
214 | ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n", | ||
215 | __FUNCTION__, phy->asd_port->phy_mask, sas_phy->id); | ||
216 | asd_update_port_links(asd_ha, phy); | ||
217 | spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); | ||
218 | } | ||
219 | |||
220 | static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy) | ||
221 | { | ||
222 | struct asd_port *port = phy->asd_port; | ||
223 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
224 | unsigned long flags; | ||
225 | |||
226 | spin_lock_irqsave(&asd_ha->asd_ports_lock, flags); | ||
227 | if (port) { | ||
228 | port->num_phys--; | ||
229 | port->phy_mask &= ~(1U << sas_phy->id); | ||
230 | phy->asd_port = NULL; | ||
231 | } | ||
232 | spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags); | ||
233 | } | ||
234 | |||
171 | static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, | 235 | static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, |
172 | struct done_list_struct *dl, | 236 | struct done_list_struct *dl, |
173 | int edb_id, int phy_id) | 237 | int edb_id, int phy_id) |
@@ -187,6 +251,7 @@ static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, | |||
187 | asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); | 251 | asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); |
188 | spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); | 252 | spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); |
189 | asd_dump_frame_rcvd(phy, dl); | 253 | asd_dump_frame_rcvd(phy, dl); |
254 | asd_form_port(ascb->ha, phy); | ||
190 | sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED); | 255 | sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED); |
191 | } | 256 | } |
192 | 257 | ||
@@ -197,6 +262,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb, | |||
197 | struct asd_ha_struct *asd_ha = ascb->ha; | 262 | struct asd_ha_struct *asd_ha = ascb->ha; |
198 | struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; | 263 | struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; |
199 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; | 264 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; |
265 | struct asd_phy *phy = &asd_ha->phys[phy_id]; | ||
200 | u8 lr_error = dl->status_block[1]; | 266 | u8 lr_error = dl->status_block[1]; |
201 | u8 retries_left = dl->status_block[2]; | 267 | u8 retries_left = dl->status_block[2]; |
202 | 268 | ||
@@ -221,6 +287,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb, | |||
221 | 287 | ||
222 | asd_turn_led(asd_ha, phy_id, 0); | 288 | asd_turn_led(asd_ha, phy_id, 0); |
223 | sas_phy_disconnected(sas_phy); | 289 | sas_phy_disconnected(sas_phy); |
290 | asd_deform_port(asd_ha, phy); | ||
224 | sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); | 291 | sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); |
225 | 292 | ||
226 | if (retries_left == 0) { | 293 | if (retries_left == 0) { |
@@ -248,6 +315,8 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb, | |||
248 | unsigned long flags; | 315 | unsigned long flags; |
249 | struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha; | 316 | struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha; |
250 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; | 317 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; |
318 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
319 | struct asd_phy *phy = &asd_ha->phys[phy_id]; | ||
251 | u8 reg = dl->status_block[1]; | 320 | u8 reg = dl->status_block[1]; |
252 | u32 cont = dl->status_block[2] << ((reg & 3)*8); | 321 | u32 cont = dl->status_block[2] << ((reg & 3)*8); |
253 | 322 | ||
@@ -284,6 +353,7 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb, | |||
284 | phy_id); | 353 | phy_id); |
285 | /* The sequencer disables all phys on that port. | 354 | /* The sequencer disables all phys on that port. |
286 | * We have to re-enable the phys ourselves. */ | 355 | * We have to re-enable the phys ourselves. */ |
356 | asd_deform_port(asd_ha, phy); | ||
287 | sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); | 357 | sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); |
288 | break; | 358 | break; |
289 | 359 | ||
@@ -351,6 +421,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
351 | u8 sb_opcode = dl->status_block[0]; | 421 | u8 sb_opcode = dl->status_block[0]; |
352 | int phy_id = sb_opcode & DL_PHY_MASK; | 422 | int phy_id = sb_opcode & DL_PHY_MASK; |
353 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; | 423 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; |
424 | struct asd_phy *phy = &asd_ha->phys[phy_id]; | ||
354 | 425 | ||
355 | if (edb > 6 || edb < 0) { | 426 | if (edb > 6 || edb < 0) { |
356 | ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", | 427 | ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", |
@@ -395,6 +466,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb, | |||
395 | asd_turn_led(asd_ha, phy_id, 0); | 466 | asd_turn_led(asd_ha, phy_id, 0); |
396 | /* the device is gone */ | 467 | /* the device is gone */ |
397 | sas_phy_disconnected(sas_phy); | 468 | sas_phy_disconnected(sas_phy); |
469 | asd_deform_port(asd_ha, phy); | ||
398 | sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); | 470 | sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); |
399 | break; | 471 | break; |
400 | case REQ_TASK_ABORT: | 472 | case REQ_TASK_ABORT: |