Skip to content

Commit

Permalink
[SCSI] qla4xxx: do not retry login to CHAP auth failed targets
Browse files Browse the repository at this point in the history
Per RFC 3720, Login Response Status Code 0x02 should not be retried.
Condensed connection error checking code to a single routine, and
added check for status class 0x02.

Signed-off-by: Karen Higgins <karen.higgins@qlogic.com>
Signed-off-by: Vikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: Ravi Anand <ravi.anand@qlogic.com>
Reviewed-by: Mike Christie <michaelc@cs.wisc.edu>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
  • Loading branch information
Vikas Chaudhary authored and James Bottomley committed May 2, 2010
1 parent c301b02 commit 821d6e5
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 43 deletions.
5 changes: 3 additions & 2 deletions drivers/scsi/qla4xxx/ql4_glbl.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,12 @@ struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha,
uint32_t index);
void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb);
int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host * ha);
int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
uint32_t fw_ddb_index, uint32_t state);
int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
uint32_t state, uint32_t conn_error);
void qla4xxx_dump_buffer(void *b, uint32_t size);
int qla4xxx_send_marker_iocb(struct scsi_qla_host *ha,
struct ddb_entry *ddb_entry, int lun, uint16_t mrkr_mod);
int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err);

extern int ql4xextended_error_logging;
extern int ql4xdiscoverywait;
Expand Down
130 changes: 90 additions & 40 deletions drivers/scsi/qla4xxx/ql4_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
struct dev_db_entry *fw_ddb_entry = NULL;
dma_addr_t fw_ddb_entry_dma;
int status = QLA_ERROR;
uint32_t conn_err;

if (ddb_entry == NULL) {
DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
Expand All @@ -525,7 +526,7 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,

if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
fw_ddb_entry_dma, NULL, NULL,
&ddb_entry->fw_ddb_device_state, NULL,
&ddb_entry->fw_ddb_device_state, &conn_err,
&ddb_entry->tcp_source_port_num,
&ddb_entry->connection_id) ==
QLA_ERROR) {
Expand Down Expand Up @@ -578,12 +579,26 @@ static int qla4xxx_update_ddb_entry(struct scsi_qla_host *ha,
fw_ddb_entry->link_local_ipv6_addr,
min(sizeof(ddb_entry->link_local_ipv6_addr),
sizeof(fw_ddb_entry->link_local_ipv6_addr)));
}

DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",
ha->host_no, __func__, fw_ddb_index,
ddb_entry->fw_ddb_device_state, status));

DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d "
"State %04x ConnErr %08x IP %pI6 "
":%04d \"%s\"\n",
__func__, fw_ddb_index,
ddb_entry->os_target_id,
ddb_entry->fw_ddb_device_state,
conn_err, fw_ddb_entry->ip_addr,
le16_to_cpu(fw_ddb_entry->port),
fw_ddb_entry->iscsi_name));
} else
DEBUG2(dev_info(&ha->pdev->dev, "%s: DDB[%d] osIdx = %d "
"State %04x ConnErr %08x IP %pI4 "
":%04d \"%s\"\n",
__func__, fw_ddb_index,
ddb_entry->os_target_id,
ddb_entry->fw_ddb_device_state,
conn_err, fw_ddb_entry->ip_addr,
le16_to_cpu(fw_ddb_entry->port),
fw_ddb_entry->iscsi_name));
exit_update_ddb:
if (fw_ddb_entry)
dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
Expand Down Expand Up @@ -629,6 +644,40 @@ static struct ddb_entry * qla4xxx_alloc_ddb(struct scsi_qla_host *ha,
return ddb_entry;
}

/**
* qla4_is_relogin_allowed - Are we allowed to login?
* @ha: Pointer to host adapter structure.
* @conn_err: Last connection error associated with the ddb
*
* This routine tests the given connection error to determine if
* we are allowed to login.
**/
int qla4_is_relogin_allowed(struct scsi_qla_host *ha, uint32_t conn_err)
{
uint32_t err_code, login_rsp_sts_class;
int relogin = 1;

err_code = ((conn_err & 0x00ff0000) >> 16);
login_rsp_sts_class = ((conn_err & 0x0000ff00) >> 8);
if (err_code == 0x1c || err_code == 0x06) {
DEBUG2(dev_info(&ha->pdev->dev,
": conn_err=0x%08x, send target completed"
" or access denied failure\n", conn_err));
relogin = 0;
}
if ((err_code == 0x08) && (login_rsp_sts_class == 0x02)) {
/* Login Response PDU returned an error.
Login Response Status in Error Code Detail
indicates login should not be retried.*/
DEBUG2(dev_info(&ha->pdev->dev,
": conn_err=0x%08x, do not retry relogin\n",
conn_err));
relogin = 0;
}

return relogin;
}

/**
* qla4xxx_configure_ddbs - builds driver ddb list
* @ha: Pointer to host adapter structure.
Expand All @@ -643,18 +692,30 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
uint32_t fw_ddb_index = 0;
uint32_t next_fw_ddb_index = 0;
uint32_t ddb_state;
uint32_t conn_err, err_code;
uint32_t conn_err;
struct ddb_entry *ddb_entry;
struct dev_db_entry *fw_ddb_entry = NULL;
dma_addr_t fw_ddb_entry_dma;
uint32_t ipv6_device;
uint32_t new_tgt;

fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
&fw_ddb_entry_dma, GFP_KERNEL);
if (fw_ddb_entry == NULL) {
DEBUG2(dev_info(&ha->pdev->dev, "%s: DMA alloc failed\n",
__func__));
return QLA_ERROR;
}

dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
fw_ddb_index = next_fw_ddb_index) {
/* First, let's see if a device exists here */
if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL,
&next_fw_ddb_index, &ddb_state,
&conn_err, NULL, NULL) ==
QLA_ERROR) {
if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
0, NULL, &next_fw_ddb_index,
&ddb_state, &conn_err,
NULL, NULL) ==
QLA_ERROR) {
DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "
"fw_ddb_index %d failed", ha->host_no,
__func__, fw_ddb_index));
Expand All @@ -671,18 +732,19 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
/* Try and login to device */
DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n",
ha->host_no, __func__, fw_ddb_index));
err_code = ((conn_err & 0x00ff0000) >> 16);
if (err_code == 0x1c || err_code == 0x06) {
DEBUG2(printk("scsi%ld: %s send target "
"completed "
"or access denied failure\n",
ha->host_no, __func__));
} else {
ipv6_device = le16_to_cpu(fw_ddb_entry->options) &
DDB_OPT_IPV6_DEVICE;
if (qla4_is_relogin_allowed(ha, conn_err) &&
((!ipv6_device &&
*((uint32_t *)fw_ddb_entry->ip_addr))
|| ipv6_device)) {
qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index,
NULL, 0, NULL, &next_fw_ddb_index,
&ddb_state, &conn_err, NULL, NULL)
== QLA_ERROR) {
NULL, 0, NULL,
&next_fw_ddb_index,
&ddb_state, &conn_err,
NULL, NULL)
== QLA_ERROR) {
DEBUG2(printk("scsi%ld: %s:"
"get_ddb_entry %d failed\n",
ha->host_no,
Expand Down Expand Up @@ -737,7 +799,6 @@ static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
struct qla4_relog_scan {
int halt_wait;
uint32_t conn_err;
uint32_t err_code;
uint32_t fw_ddb_index;
uint32_t next_fw_ddb_index;
uint32_t fw_ddb_device_state;
Expand All @@ -747,18 +808,7 @@ static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs)
{
struct ddb_entry *ddb_entry;

/*
* Don't want to do a relogin if connection
* error is 0x1c.
*/
rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16);
if (rs->err_code == 0x1c || rs->err_code == 0x06) {
DEBUG2(printk(
"scsi%ld: %s send target"
" completed or "
"access denied failure\n",
ha->host_no, __func__));
} else {
if (qla4_is_relogin_allowed(ha, rs->conn_err)) {
/* We either have a device that is in
* the process of relogging in or a
* device that is waiting to be
Expand Down Expand Up @@ -1411,8 +1461,8 @@ static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
*
* This routine processes a Decive Database Changed AEN Event.
**/
int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
uint32_t fw_ddb_index, uint32_t state)
int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha, uint32_t fw_ddb_index,
uint32_t state, uint32_t conn_err)
{
struct ddb_entry * ddb_entry;
uint32_t old_fw_ddb_device_state;
Expand Down Expand Up @@ -1470,21 +1520,21 @@ int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,

/*
* Relogin if device state changed to a not active state.
* However, do not relogin if this aen is a result of an IOCTL
* logout (DF_NO_RELOGIN) or if this is a discovered device.
* However, do not relogin if a RELOGIN is in process, or
* we are not allowed to relogin to this DDB.
*/
if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED &&
!test_bit(DF_RELOGIN, &ddb_entry->flags) &&
!test_bit(DF_NO_RELOGIN, &ddb_entry->flags) &&
!test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) {
qla4_is_relogin_allowed(ha, conn_err)) {
/*
* This triggers a relogin. After the relogin_timer
* expires, the relogin gets scheduled. We must wait a
* minimum amount of time since receiving an 0x8014 AEN
* with failed device_state or a logout response before
* we can issue another relogin.
*/
/* Firmware padds this timeout: (time2wait +1).
/* Firmware pads this timeout: (time2wait +1).
* Driver retry to login should be longer than F/W.
* Otherwise F/W will fail
* set_ddb() mbx cmd with 0x4005 since it still
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/qla4xxx/ql4_isr.c
Original file line number Diff line number Diff line change
Expand Up @@ -838,7 +838,7 @@ void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
qla4xxx_reinitialize_ddb_list(ha);
} else if (mbox_sts[1] == 1) { /* Specific device. */
qla4xxx_process_ddb_changed(ha, mbox_sts[2],
mbox_sts[3]);
mbox_sts[3], mbox_sts[4]);
}
break;
}
Expand Down

0 comments on commit 821d6e5

Please sign in to comment.