[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>
This commit is contained in:
parent
088406bcf6
commit
3f048109d9
|
@ -112,6 +112,21 @@ static int asd_init_phy(struct asd_phy *phy)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void asd_init_ports(struct asd_ha_struct *asd_ha)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
spin_lock_init(&asd_ha->asd_ports_lock);
|
||||||
|
for (i = 0; i < ASD_MAX_PHYS; i++) {
|
||||||
|
struct asd_port *asd_port = &asd_ha->asd_ports[i];
|
||||||
|
|
||||||
|
memset(asd_port->sas_addr, 0, SAS_ADDR_SIZE);
|
||||||
|
memset(asd_port->attached_sas_addr, 0, SAS_ADDR_SIZE);
|
||||||
|
asd_port->phy_mask = 0;
|
||||||
|
asd_port->num_phys = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int asd_init_phys(struct asd_ha_struct *asd_ha)
|
static int asd_init_phys(struct asd_ha_struct *asd_ha)
|
||||||
{
|
{
|
||||||
u8 i;
|
u8 i;
|
||||||
|
@ -121,6 +136,7 @@ static int asd_init_phys(struct asd_ha_struct *asd_ha)
|
||||||
struct asd_phy *phy = &asd_ha->phys[i];
|
struct asd_phy *phy = &asd_ha->phys[i];
|
||||||
|
|
||||||
phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
|
phy->phy_desc = &asd_ha->hw_prof.phy_desc[i];
|
||||||
|
phy->asd_port = NULL;
|
||||||
|
|
||||||
phy->sas_phy.enabled = 0;
|
phy->sas_phy.enabled = 0;
|
||||||
phy->sas_phy.id = i;
|
phy->sas_phy.id = i;
|
||||||
|
@ -658,6 +674,8 @@ int asd_init_hw(struct asd_ha_struct *asd_ha)
|
||||||
goto Out;
|
goto Out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asd_init_ports(asd_ha);
|
||||||
|
|
||||||
err = asd_init_scbs(asd_ha);
|
err = asd_init_scbs(asd_ha);
|
||||||
if (err) {
|
if (err) {
|
||||||
asd_printk("couldn't initialize scbs for %s\n",
|
asd_printk("couldn't initialize scbs for %s\n",
|
||||||
|
|
|
@ -193,6 +193,16 @@ struct asd_seq_data {
|
||||||
struct asd_ascb **escb_arr; /* array of pointers to escbs */
|
struct asd_ascb **escb_arr; /* array of pointers to escbs */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* This is an internal port structure. These are used to get accurate
|
||||||
|
* phy_mask for updating DDB 0.
|
||||||
|
*/
|
||||||
|
struct asd_port {
|
||||||
|
u8 sas_addr[SAS_ADDR_SIZE];
|
||||||
|
u8 attached_sas_addr[SAS_ADDR_SIZE];
|
||||||
|
u32 phy_mask;
|
||||||
|
int num_phys;
|
||||||
|
};
|
||||||
|
|
||||||
/* This is the Host Adapter structure. It describes the hardware
|
/* This is the Host Adapter structure. It describes the hardware
|
||||||
* SAS adapter.
|
* SAS adapter.
|
||||||
*/
|
*/
|
||||||
|
@ -211,6 +221,8 @@ struct asd_ha_struct {
|
||||||
struct hw_profile hw_prof;
|
struct hw_profile hw_prof;
|
||||||
|
|
||||||
struct asd_phy phys[ASD_MAX_PHYS];
|
struct asd_phy phys[ASD_MAX_PHYS];
|
||||||
|
spinlock_t asd_ports_lock;
|
||||||
|
struct asd_port asd_ports[ASD_MAX_PHYS];
|
||||||
struct asd_sas_port ports[ASD_MAX_PHYS];
|
struct asd_sas_port ports[ASD_MAX_PHYS];
|
||||||
|
|
||||||
struct dma_pool *scb_pool;
|
struct dma_pool *scb_pool;
|
||||||
|
|
|
@ -786,8 +786,6 @@ static void asd_remove_driver_attrs(struct device_driver *driver)
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sas_domain_function_template aic94xx_transport_functions = {
|
static struct sas_domain_function_template aic94xx_transport_functions = {
|
||||||
.lldd_port_formed = asd_update_port_links,
|
|
||||||
|
|
||||||
.lldd_dev_found = asd_dev_found,
|
.lldd_dev_found = asd_dev_found,
|
||||||
.lldd_dev_gone = asd_dev_gone,
|
.lldd_dev_gone = asd_dev_gone,
|
||||||
|
|
||||||
|
|
|
@ -733,6 +733,7 @@ struct asd_phy {
|
||||||
|
|
||||||
struct sas_identify_frame *identify_frame;
|
struct sas_identify_frame *identify_frame;
|
||||||
struct asd_dma_tok *id_frm_tok;
|
struct asd_dma_tok *id_frm_tok;
|
||||||
|
struct asd_port *asd_port;
|
||||||
|
|
||||||
u8 frame_rcvd[ASD_EDB_SIZE];
|
u8 frame_rcvd[ASD_EDB_SIZE];
|
||||||
};
|
};
|
||||||
|
|
|
@ -168,6 +168,70 @@ static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void asd_form_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct asd_port *free_port = NULL;
|
||||||
|
struct asd_port *port;
|
||||||
|
struct asd_sas_phy *sas_phy = &phy->sas_phy;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&asd_ha->asd_ports_lock, flags);
|
||||||
|
if (!phy->asd_port) {
|
||||||
|
for (i = 0; i < ASD_MAX_PHYS; i++) {
|
||||||
|
port = &asd_ha->asd_ports[i];
|
||||||
|
|
||||||
|
/* Check for wide port */
|
||||||
|
if (port->num_phys > 0 &&
|
||||||
|
memcmp(port->sas_addr, sas_phy->sas_addr,
|
||||||
|
SAS_ADDR_SIZE) == 0 &&
|
||||||
|
memcmp(port->attached_sas_addr,
|
||||||
|
sas_phy->attached_sas_addr,
|
||||||
|
SAS_ADDR_SIZE) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find a free port */
|
||||||
|
if (port->num_phys == 0 && free_port == NULL) {
|
||||||
|
free_port = port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use a free port if this doesn't form a wide port */
|
||||||
|
if (i >= ASD_MAX_PHYS) {
|
||||||
|
port = free_port;
|
||||||
|
BUG_ON(!port);
|
||||||
|
memcpy(port->sas_addr, sas_phy->sas_addr,
|
||||||
|
SAS_ADDR_SIZE);
|
||||||
|
memcpy(port->attached_sas_addr,
|
||||||
|
sas_phy->attached_sas_addr,
|
||||||
|
SAS_ADDR_SIZE);
|
||||||
|
}
|
||||||
|
port->num_phys++;
|
||||||
|
port->phy_mask |= (1U << sas_phy->id);
|
||||||
|
phy->asd_port = port;
|
||||||
|
}
|
||||||
|
ASD_DPRINTK("%s: updating phy_mask 0x%x for phy%d\n",
|
||||||
|
__FUNCTION__, phy->asd_port->phy_mask, sas_phy->id);
|
||||||
|
asd_update_port_links(asd_ha, phy);
|
||||||
|
spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void asd_deform_port(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
|
||||||
|
{
|
||||||
|
struct asd_port *port = phy->asd_port;
|
||||||
|
struct asd_sas_phy *sas_phy = &phy->sas_phy;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&asd_ha->asd_ports_lock, flags);
|
||||||
|
if (port) {
|
||||||
|
port->num_phys--;
|
||||||
|
port->phy_mask &= ~(1U << sas_phy->id);
|
||||||
|
phy->asd_port = NULL;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&asd_ha->asd_ports_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
|
static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
|
||||||
struct done_list_struct *dl,
|
struct done_list_struct *dl,
|
||||||
int edb_id, int phy_id)
|
int edb_id, int phy_id)
|
||||||
|
@ -187,6 +251,7 @@ static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb,
|
||||||
asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
|
asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr);
|
||||||
spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
|
spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags);
|
||||||
asd_dump_frame_rcvd(phy, dl);
|
asd_dump_frame_rcvd(phy, dl);
|
||||||
|
asd_form_port(ascb->ha, phy);
|
||||||
sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
|
sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,6 +262,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
|
||||||
struct asd_ha_struct *asd_ha = ascb->ha;
|
struct asd_ha_struct *asd_ha = ascb->ha;
|
||||||
struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
|
struct sas_ha_struct *sas_ha = &asd_ha->sas_ha;
|
||||||
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
|
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
|
||||||
|
struct asd_phy *phy = &asd_ha->phys[phy_id];
|
||||||
u8 lr_error = dl->status_block[1];
|
u8 lr_error = dl->status_block[1];
|
||||||
u8 retries_left = dl->status_block[2];
|
u8 retries_left = dl->status_block[2];
|
||||||
|
|
||||||
|
@ -221,6 +287,7 @@ static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb,
|
||||||
|
|
||||||
asd_turn_led(asd_ha, phy_id, 0);
|
asd_turn_led(asd_ha, phy_id, 0);
|
||||||
sas_phy_disconnected(sas_phy);
|
sas_phy_disconnected(sas_phy);
|
||||||
|
asd_deform_port(asd_ha, phy);
|
||||||
sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
|
sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR);
|
||||||
|
|
||||||
if (retries_left == 0) {
|
if (retries_left == 0) {
|
||||||
|
@ -248,6 +315,8 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
|
struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha;
|
||||||
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
|
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
|
||||||
|
struct asd_ha_struct *asd_ha = ascb->ha;
|
||||||
|
struct asd_phy *phy = &asd_ha->phys[phy_id];
|
||||||
u8 reg = dl->status_block[1];
|
u8 reg = dl->status_block[1];
|
||||||
u32 cont = dl->status_block[2] << ((reg & 3)*8);
|
u32 cont = dl->status_block[2] << ((reg & 3)*8);
|
||||||
|
|
||||||
|
@ -284,6 +353,7 @@ static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb,
|
||||||
phy_id);
|
phy_id);
|
||||||
/* The sequencer disables all phys on that port.
|
/* The sequencer disables all phys on that port.
|
||||||
* We have to re-enable the phys ourselves. */
|
* We have to re-enable the phys ourselves. */
|
||||||
|
asd_deform_port(asd_ha, phy);
|
||||||
sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
|
sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -351,6 +421,7 @@ static void escb_tasklet_complete(struct asd_ascb *ascb,
|
||||||
u8 sb_opcode = dl->status_block[0];
|
u8 sb_opcode = dl->status_block[0];
|
||||||
int phy_id = sb_opcode & DL_PHY_MASK;
|
int phy_id = sb_opcode & DL_PHY_MASK;
|
||||||
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
|
struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id];
|
||||||
|
struct asd_phy *phy = &asd_ha->phys[phy_id];
|
||||||
|
|
||||||
if (edb > 6 || edb < 0) {
|
if (edb > 6 || edb < 0) {
|
||||||
ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n",
|
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,
|
||||||
asd_turn_led(asd_ha, phy_id, 0);
|
asd_turn_led(asd_ha, phy_id, 0);
|
||||||
/* the device is gone */
|
/* the device is gone */
|
||||||
sas_phy_disconnected(sas_phy);
|
sas_phy_disconnected(sas_phy);
|
||||||
|
asd_deform_port(asd_ha, phy);
|
||||||
sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
|
sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT);
|
||||||
break;
|
break;
|
||||||
case REQ_TASK_ABORT:
|
case REQ_TASK_ABORT:
|
||||||
|
|
|
@ -1369,10 +1369,9 @@ int asd_start_seqs(struct asd_ha_struct *asd_ha)
|
||||||
* port_map_by_links is also used as the conn_mask byte in the
|
* port_map_by_links is also used as the conn_mask byte in the
|
||||||
* initiator/target port DDB.
|
* initiator/target port DDB.
|
||||||
*/
|
*/
|
||||||
void asd_update_port_links(struct asd_sas_phy *sas_phy)
|
void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy)
|
||||||
{
|
{
|
||||||
struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha;
|
const u8 phy_mask = (u8) phy->asd_port->phy_mask;
|
||||||
const u8 phy_mask = (u8) sas_phy->port->phy_mask;
|
|
||||||
u8 phy_is_up;
|
u8 phy_is_up;
|
||||||
u8 mask;
|
u8 mask;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
|
@ -64,7 +64,7 @@ int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask);
|
||||||
int asd_init_seqs(struct asd_ha_struct *asd_ha);
|
int asd_init_seqs(struct asd_ha_struct *asd_ha);
|
||||||
int asd_start_seqs(struct asd_ha_struct *asd_ha);
|
int asd_start_seqs(struct asd_ha_struct *asd_ha);
|
||||||
|
|
||||||
void asd_update_port_links(struct asd_sas_phy *phy);
|
void asd_update_port_links(struct asd_ha_struct *asd_ha, struct asd_phy *phy);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue