aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx/aic94xx_scb.c
diff options
context:
space:
mode:
authormalahal@us.ibm.com <malahal@us.ibm.com>2006-10-04 20:28:37 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-11-09 00:27:48 -0500
commit3f048109d9c4f8bb028ccb0d256ab65eb44f5988 (patch)
tree4a37dcbda611cf7e67f1dc27bc1843a17ac4c3e2 /drivers/scsi/aic94xx/aic94xx_scb.c
parent088406bcf66d6c7fd8a5c04c00aa410ae9077403 (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.c72
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
171static 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
220static 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
171static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, 235static 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: