aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/aic94xx/aic94xx_scb.c
diff options
context:
space:
mode:
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 52c6ea4fbf71..14d5d8c2ee13 100644
--- a/drivers/scsi/aic94xx/aic94xx_scb.c
+++ b/drivers/scsi/aic94xx/aic94xx_scb.c
@@ -169,6 +169,70 @@ static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
169 } 169 }
170} 170}
171 171
172static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
173{
174 int i;
175 struct asd_port *free_port = NULL;
176 struct asd_port *port;
177 struct asd_sas_phy *sas_phy = &phy->sas_phy;
178 unsigned long flags;
179
180 spin_lock_irqsave(&asd_ha->asd_ports_lock, flags);
181 if (!phy->asd_port) {
182 for (i = 0; i < ASD_MAX_PHYS; i++) {
183 port = &asd_ha->asd_ports[i];
184
185 /* Check for wide port */
186 if (port->num_phys > 0 &&
187 memcmp(port->sas_addr, sas_phy->sas_addr,
188 SAS_ADDR_SIZE) == 0 &&
189 memcmp(port->attached_sas_addr,
190 sas_phy->attached_sas_addr,
191 SAS_ADDR_SIZE) == 0) {
192 break;
193 }
194
195 /* Find a free port */
196 if (port->num_phys == 0 && free_port == NULL) {
197 free_port = port;
198 }
199 }
200
201 /* Use a free port if this doesn't form a wide port */
202 if (i >= ASD_MAX_PHYS) {
203 port = free_port;
204 BUG_ON(!port);
205 memcpy(port->sas_addr, sas_phy->sas_addr,
206 SAS_ADDR_SIZE);
207 memcpy(port->attached_sas_addr,
208 sas_phy->attached_sas_addr,
209 SAS_ADDR_SIZE);
210 }
211 port->num_phys++;
212 port->phy_mask |= (1U << sas_phy->id);
213 phy->asd_port = port;
214 }
215 ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
216 __FUNCTION__, phy->asd_port->phy_mask, sas_phy->id);
217 asd_update_port_links(asd_ha, phy);
218 spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
219}
220
221static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
222{
223 struct asd_port *port = phy->asd_port;
224 struct asd_sas_phy *sas_phy = &phy->sas_phy;
225 unsigned long flags;
226
227 spin_lock_irqsave(&asd_ha->asd_ports_lock, flags);
228 if (port) {
229 port->num_phys--;
230 port->phy_mask &= ~(1U << sas_phy->id);
231 phy->asd_port = NULL;
232 }
233 spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
234}
235
172static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, 236static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
173 struct done_list_struct *dl, 237 struct done_list_struct *dl,
174 int edb_id, int phy_id) 238 int edb_id, int phy_id)
@@ -188,6 +252,7 @@ static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
188 asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); 252 asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
189 spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); 253 spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
190 asd_dump_frame_rcvd(phy, dl); 254 asd_dump_frame_rcvd(phy, dl);
255 asd_form_port(ascb->ha, phy);
191 sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED); 256 sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
192} 257}
193 258
@@ -198,6 +263,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
198 struct asd_ha_struct *asd_ha = ascb->ha; 263 struct asd_ha_struct *asd_ha = ascb->ha;
199 struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; 264 struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
200 struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; 265 struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
266 struct asd_phy *phy = &asd_ha->phys[phy_id];
201 u8 lr_error = dl->status_block[1]; 267 u8 lr_error = dl->status_block[1];
202 u8 retries_left = dl->status_block[2]; 268 u8 retries_left = dl->status_block[2];
203 269
@@ -222,6 +288,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
222 288
223 asd_turn_led(asd_ha, phy_id, 0); 289 asd_turn_led(asd_ha, phy_id, 0);
224 sas_phy_disconnected(sas_phy); 290 sas_phy_disconnected(sas_phy);
291 asd_deform_port(asd_ha, phy);
225 sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); 292 sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
226 293
227 if (retries_left == 0) { 294 if (retries_left == 0) {
@@ -249,6 +316,8 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
249 unsigned long flags; 316 unsigned long flags;
250 struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha; 317 struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
251 struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; 318 struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
319 struct asd_ha_struct *asd_ha = ascb->ha;
320 struct asd_phy *phy = &asd_ha->phys[phy_id];
252 u8 reg = dl->status_block[1]; 321 u8 reg = dl->status_block[1];
253 u32 cont = dl->status_block[2] << ((reg & 3)*8); 322 u32 cont = dl->status_block[2] << ((reg & 3)*8);
254 323
@@ -285,6 +354,7 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
285 phy_id); 354 phy_id);
286 /* The sequencer disables all phys on that port. 355 /* The sequencer disables all phys on that port.
287 * We have to re-enable the phys ourselves. */ 356 * We have to re-enable the phys ourselves. */
357 asd_deform_port(asd_ha, phy);
288 sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); 358 sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
289 break; 359 break;
290 360
@@ -385,6 +455,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
385 u8 sb_opcode = dl->status_block[0]; 455 u8 sb_opcode = dl->status_block[0];
386 int phy_id = sb_opcode & DL_PHY_MASK; 456 int phy_id = sb_opcode & DL_PHY_MASK;
387 struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; 457 struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
458 struct asd_phy *phy = &asd_ha->phys[phy_id];
388 459
389 if (edb > 6 || edb < 0) { 460 if (edb > 6 || edb < 0) {
390 ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", 461 ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
@@ -497,6 +568,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
497 asd_turn_led(asd_ha, phy_id, 0); 568 asd_turn_led(asd_ha, phy_id, 0);
498 /* the device is gone */ 569 /* the device is gone */
499 sas_phy_disconnected(sas_phy); 570 sas_phy_disconnected(sas_phy);
571 asd_deform_port(asd_ha, phy);
500 sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); 572 sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
501 break; 573 break;
502 default: 574 default: