scsi: qla2xxx: SAN congestion management implementation
authorShyam Sundar <ssundar@marvell.com>
Tue, 30 Jun 2020 10:22:29 +0000 (03:22 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 2 Jul 2020 02:25:09 +0000 (22:25 -0400)
* Firmware Initialization with SCM enabled based on NVRAM setting and
  firmware support (About Firmware).

* Enable PUREX and add support for fabric performance impact
  notification (FPIN) handling.

* Allocate a default PUREX item for each vha to handle memory allocation
  failures in ISR.

Link: https://lore.kernel.org/r/20200630102229.29660-3-njavali@marvell.com
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.com>
Reviewed-by: James Smart <james.smart@broadcom.com>
Signed-off-by: Shyam Sundar <ssundar@marvell.com>
Signed-off-by: Arun Easi <aeasi@marvell.com>
Signed-off-by: Nilesh Javali <njavali@marvell.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/qla2xxx/qla_dbg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c

index 911c785..1be811a 100644 (file)
  * ----------------------------------------------------------------------
  * |             Level            |   Last Value Used  |     Holes     |
  * ----------------------------------------------------------------------
- * | Module Init and Probe        |       0x0193       | 0x0146         |
- * |                              |                    | 0x015b-0x0160 |
- * |                              |                    | 0x016e                |
- * | Mailbox commands             |       0x1206       | 0x11a2-0x11ff |
+ * | Module Init and Probe        |       0x0199       |                |
+ * | Mailbox commands             |       0x1206       | 0x11a5-0x11ff |
  * | Device Discovery             |       0x2134       | 0x210e-0x2116  |
  * |                             |                    | 0x211a         |
  * |                              |                    | 0x211c-0x2128  |
  * |                              |                    | 0x3036,0x3038  |
  * |                              |                    | 0x303a                |
  * | DPC Thread                   |       0x4023       | 0x4002,0x4013  |
- * | Async Events                 |       0x5090       | 0x502b-0x502f  |
- * |                             |                    | 0x5047         |
- * |                              |                    | 0x5084,0x5075 |
- * |                              |                    | 0x503d,0x5044  |
- * |                              |                    | 0x505f                |
+ * | Async Events                 |       0x509c       |                |
  * | Timer Routines               |       0x6012       |                |
  * | User Space Interactions      |       0x70e3       | 0x7018,0x702e  |
  * |                             |                    | 0x7020,0x7024  |
@@ -2662,7 +2656,6 @@ ql_dump_regs(uint level, scsi_qla_host_t *vha, uint id)
                    "mbox[%d] %#04x\n", i, rd_reg_word(mbx_reg));
 }
 
-
 void
 ql_dump_buffer(uint level, scsi_qla_host_t *vha, uint id, const void *buf,
               uint size)
index 9a0f231..8c92af5 100644 (file)
@@ -1055,6 +1055,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
 #define MBA_LIP_F8             0x8016  /* Received a LIP F8. */
 #define MBA_LOOP_INIT_ERR      0x8017  /* Loop Initialization Error. */
 #define MBA_FABRIC_AUTH_REQ    0x801b  /* Fabric Authentication Required. */
+#define MBA_CONGN_NOTI_RECV    0x801e  /* Congestion Notification Received */
 #define MBA_SCSI_COMPLETION    0x8020  /* SCSI Command Complete. */
 #define MBA_CTIO_COMPLETION    0x8021  /* CTIO Complete. */
 #define MBA_IP_COMPLETION      0x8022  /* IP Transmit Command Complete. */
@@ -1510,6 +1511,25 @@ typedef struct {
        uint8_t  reserved_3[26];
 } init_cb_t;
 
+/* Special Features Control Block */
+struct init_sf_cb {
+       uint8_t format;
+       uint8_t reserved0;
+       /*
+        * BIT 15-14 = Reserved
+        * BIT_13 = SAN Congestion Management (1 - Enabled, 0 - Disabled)
+        * BIT_12 = Remote Write Optimization (1 - Enabled, 0 - Disabled)
+        * BIT 11-0 = Reserved
+        */
+       uint16_t flags;
+       uint8_t reserved1[32];
+       uint16_t discard_OHRB_timeout_value;
+       uint16_t remote_write_opt_queue_num;
+       uint8_t reserved2[40];
+       uint8_t scm_related_parameter[16];
+       uint8_t reserved3[32];
+};
+
 /*
  * Get Link Status mailbox command return buffer.
  */
@@ -2183,6 +2203,8 @@ typedef struct {
        struct dsd64 rsp_dsd;
 } ms_iocb_entry_t;
 
+#define SCM_EDC_ACC_RECEIVED           BIT_6
+#define SCM_RDF_ACC_RECEIVED           BIT_7
 
 /*
  * ISP queue - Mailbox Command entry structure definition.
@@ -3852,6 +3874,12 @@ struct qla_hw_data {
                uint32_t        n2n_bigger:1;
                uint32_t        secure_adapter:1;
                uint32_t        secure_fw:1;
+                               /* Supported by Adapter */
+               uint32_t        scm_supported_a:1;
+                               /* Supported by Firmware */
+               uint32_t        scm_supported_f:1;
+                               /* Enabled in Driver */
+               uint32_t        scm_enabled:1;
        } flags;
 
        uint16_t max_exchg;
@@ -4169,6 +4197,13 @@ struct qla_hw_data {
        int             init_cb_size;
        dma_addr_t      ex_init_cb_dma;
        struct ex_init_cb_81xx *ex_init_cb;
+       dma_addr_t      sf_init_cb_dma;
+       struct init_sf_cb *sf_init_cb;
+
+       void            *scm_fpin_els_buff;
+       uint64_t        scm_fpin_els_buff_size;
+       bool            scm_fpin_valid;
+       bool            scm_fpin_payload_size;
 
        void            *async_pd;
        dma_addr_t      async_pd_dma;
@@ -4231,6 +4266,12 @@ struct qla_hw_data {
 #define FW_ATTR_H_NVME         BIT_10
 #define FW_ATTR_H_NVME_UPDATED  BIT_14
 
+       /* About firmware SCM support */
+#define FW_ATTR_EXT0_SCM_SUPPORTED     BIT_12
+       /* Brocade fabric attached */
+#define FW_ATTR_EXT0_SCM_BROCADE       0x00001000
+       /* Cisco fabric attached */
+#define FW_ATTR_EXT0_SCM_CISCO         0x00002000
        uint16_t        fw_attributes_ext[2];
        uint32_t        fw_memory_size;
        uint32_t        fw_transfer_size;
@@ -4541,6 +4582,13 @@ struct purex_item {
        } iocb;
 };
 
+#define SCM_FLAG_RDF_REJECT            0x00
+#define SCM_FLAG_RDF_COMPLETED         0x01
+
+#define QLA_CON_PRIMITIVE_RECEIVED     0x1
+#define QLA_CONGESTION_ARB_WARNING     0x1
+#define QLA_CONGESTION_ARB_ALARM       0X2
+
 /*
  * Qlogic scsi host structure
  */
@@ -4749,6 +4797,7 @@ typedef struct scsi_qla_host {
        __le16 dport_data[4];
        struct list_head gpnid_list;
        struct fab_scan scan;
+       uint8_t scm_fabric_connection_flags;
 
        unsigned int irq_offset;
 } scsi_qla_host_t;
index d1e12a2..49403fb 100644 (file)
@@ -723,6 +723,8 @@ struct ct_entry_24xx {
        struct dsd64 dsd[2];
 };
 
+#define PURX_ELS_HEADER_SIZE   0x18
+
 /*
  * ISP queue - PUREX IOCB entry structure definition
  */
@@ -2020,7 +2022,9 @@ struct nvram_81xx {
         * BIT 0    = Extended BB credits for LR
         * BIT 1    = Virtual Fabric Enable
         * BIT 2-5  = Distance Support if BIT 0 is on
-        * BIT 6-15 = Unused
+        * BIT 6    = Prefer FCP
+        * BIT 7    = SCM Disabled if BIT is set (1)
+        * BIT 8-15 = Unused
         */
        uint16_t enhanced_features;
 
index 9cf33d0..0ced18f 100644 (file)
@@ -127,6 +127,7 @@ int qla_post_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport);
 void qla_do_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport);
 int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *);
 void qla_rscn_replay(fc_port_t *fcport);
+void qla24xx_free_purex_item(struct purex_item *item);
 extern bool qla24xx_risc_firmware_invalid(uint32_t *);
 
 /*
index 6cc1a82..b4762d5 100644 (file)
@@ -3749,7 +3749,7 @@ enable_82xx_npiv:
                }
 
                /* Enable PUREX PASSTHRU */
-               if (ql2xrdpenable)
+               if (ql2xrdpenable || ha->flags.scm_supported_f)
                        qla25xx_set_els_cmds_supported(vha);
        } else
                goto failed;
@@ -3962,7 +3962,7 @@ qla24xx_update_fw_options(scsi_qla_host_t *vha)
                        ha->fw_options[2] &= ~BIT_8;
        }
 
-       if (ql2xrdpenable)
+       if (ql2xrdpenable || ha->flags.scm_supported_f)
                ha->fw_options[1] |= ADD_FO1_ENABLE_PUREX_IOCB;
 
        /* Enable Async 8130/8131 events -- transceiver insertion/removal */
@@ -8519,6 +8519,11 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
                icb->node_name[0] &= 0xF0;
        }
 
+       if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
+               if ((nv->enhanced_features & BIT_7) == 0)
+                       ha->flags.scm_supported_a = 1;
+       }
+
        /* Set host adapter parameters. */
        ha->flags.disable_risc_code_load = 0;
        ha->flags.enable_lip_reset = 0;
index 3bbfff2..7be32de 100644 (file)
@@ -22,6 +22,31 @@ static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
 static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
 static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
        sts_entry_t *);
+static void qla27xx_process_purex_fpin(struct scsi_qla_host *vha,
+       struct purex_item *item);
+static struct purex_item *qla24xx_alloc_purex_item(scsi_qla_host_t *vha,
+       uint16_t size);
+static struct purex_item *qla24xx_copy_std_pkt(struct scsi_qla_host *vha,
+       void *pkt);
+static struct purex_item *qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha,
+       void **pkt, struct rsp_que **rsp);
+
+static void
+qla27xx_process_purex_fpin(struct scsi_qla_host *vha, struct purex_item *item)
+{
+       void *pkt = &item->iocb;
+       uint16_t pkt_size = item->size;
+
+       ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508d,
+              "%s: Enter\n", __func__);
+
+       ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508e,
+              "-------- ELS REQ -------\n");
+       ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x508f,
+                      pkt, pkt_size);
+
+       fc_host_fpin_rcv(vha->host, pkt_size, (char *)pkt);
+}
 
 const char *const port_state_str[] = {
        "Unknown",
@@ -819,7 +844,7 @@ qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
  * @vha: SCSI driver HA context
  * @pkt: ELS packet
  */
-struct purex_item
+static struct purex_item
 *qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
 {
        struct purex_item *item;
@@ -834,6 +859,111 @@ struct purex_item
 }
 
 /**
+ * qla27xx_copy_fpin_pkt() - Copy over fpin packets that can
+ * span over multiple IOCBs.
+ * @vha: SCSI driver HA context
+ * @pkt: ELS packet
+ * @rsp: Response queue
+ */
+static struct purex_item *
+qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
+                     struct rsp_que **rsp)
+{
+       struct purex_entry_24xx *purex = *pkt;
+       struct rsp_que *rsp_q = *rsp;
+       sts_cont_entry_t *new_pkt;
+       uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
+       uint16_t buffer_copy_offset = 0;
+       uint16_t entry_count, entry_count_remaining;
+       struct purex_item *item;
+       void *fpin_pkt = NULL;
+
+       total_bytes = le16_to_cpu(purex->frame_size & 0x0FFF)
+           - PURX_ELS_HEADER_SIZE;
+       pending_bytes = total_bytes;
+       entry_count = entry_count_remaining = purex->entry_count;
+       no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
+                  sizeof(purex->els_frame_payload) : pending_bytes;
+       ql_log(ql_log_info, vha, 0x509a,
+              "FPIN ELS, frame_size 0x%x, entry count %d\n",
+              total_bytes, entry_count);
+
+       item = qla24xx_alloc_purex_item(vha, total_bytes);
+       if (!item)
+               return item;
+
+       fpin_pkt = &item->iocb;
+
+       memcpy(fpin_pkt, &purex->els_frame_payload[0], no_bytes);
+       buffer_copy_offset += no_bytes;
+       pending_bytes -= no_bytes;
+       --entry_count_remaining;
+
+       ((response_t *)purex)->signature = RESPONSE_PROCESSED;
+       wmb();
+
+       do {
+               while ((total_bytes > 0) && (entry_count_remaining > 0)) {
+                       if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
+                               ql_dbg(ql_dbg_async, vha, 0x5084,
+                                      "Ran out of IOCBs, partial data 0x%x\n",
+                                      buffer_copy_offset);
+                               cpu_relax();
+                               continue;
+                       }
+
+                       new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
+                       *pkt = new_pkt;
+
+                       if (new_pkt->entry_type != STATUS_CONT_TYPE) {
+                               ql_log(ql_log_warn, vha, 0x507a,
+                                      "Unexpected IOCB type, partial data 0x%x\n",
+                                      buffer_copy_offset);
+                               break;
+                       }
+
+                       rsp_q->ring_index++;
+                       if (rsp_q->ring_index == rsp_q->length) {
+                               rsp_q->ring_index = 0;
+                               rsp_q->ring_ptr = rsp_q->ring;
+                       } else {
+                               rsp_q->ring_ptr++;
+                       }
+                       no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
+                           sizeof(new_pkt->data) : pending_bytes;
+                       if ((buffer_copy_offset + no_bytes) <= total_bytes) {
+                               memcpy(((uint8_t *)fpin_pkt +
+                                   buffer_copy_offset), new_pkt->data,
+                                   no_bytes);
+                               buffer_copy_offset += no_bytes;
+                               pending_bytes -= no_bytes;
+                               --entry_count_remaining;
+                       } else {
+                               ql_log(ql_log_warn, vha, 0x5044,
+                                      "Attempt to copy more that we got, optimizing..%x\n",
+                                      buffer_copy_offset);
+                               memcpy(((uint8_t *)fpin_pkt +
+                                   buffer_copy_offset), new_pkt->data,
+                                   total_bytes - buffer_copy_offset);
+                       }
+
+                       ((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
+                       wmb();
+               }
+
+               if (pending_bytes != 0 || entry_count_remaining != 0) {
+                       ql_log(ql_log_fatal, vha, 0x508b,
+                              "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n",
+                              total_bytes, entry_count_remaining);
+                       qla24xx_free_purex_item(item);
+                       return NULL;
+               }
+       } while (entry_count_remaining > 0);
+       host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes);
+       return item;
+}
+
+/**
  * qla2x00_async_event() - Process aynchronous events.
  * @vha: SCSI driver HA context
  * @rsp: response queue
@@ -1346,6 +1476,19 @@ global_port_update:
                        qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
                }
                break;
+       case MBA_CONGN_NOTI_RECV:
+               if (!ha->flags.scm_enabled ||
+                   mb[1] != QLA_CON_PRIMITIVE_RECEIVED)
+                       break;
+
+               if (mb[2] == QLA_CONGESTION_ARB_WARNING) {
+                       ql_dbg(ql_dbg_async, vha, 0x509b,
+                              "Congestion Warning %04x %04x.\n", mb[1], mb[2]);
+               } else if (mb[2] == QLA_CONGESTION_ARB_ALARM) {
+                       ql_log(ql_log_warn, vha, 0x509b,
+                              "Congestion Alarm %04x %04x.\n", mb[1], mb[2]);
+               }
+               break;
        /* case MBA_RIO_RESPONSE: */
        case MBA_ZIO_RESPONSE:
                ql_dbg(ql_dbg_async, vha, 0x5015,
@@ -3273,6 +3416,7 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
 {
        struct sts_entry_24xx *pkt;
        struct qla_hw_data *ha = vha->hw;
+       struct purex_entry_24xx *purex_entry;
        struct purex_item *pure_item;
 
        if (!ha->flags.fw_started)
@@ -3328,7 +3472,6 @@ process_err:
                                pure_item = qla24xx_copy_std_pkt(vha, pkt);
                                if (!pure_item)
                                        break;
-
                                qla24xx_queue_purex_item(vha, pure_item,
                                                         qla24xx_process_abts);
                                break;
@@ -3378,29 +3521,40 @@ process_err:
                            (struct vp_ctrl_entry_24xx *)pkt);
                        break;
                case PUREX_IOCB_TYPE:
-               {
-                       struct purex_entry_24xx *purex = (void *)pkt;
-
-                       if (purex->els_frame_payload[3] != ELS_RDP) {
-                               ql_dbg(ql_dbg_init, vha, 0x5091,
-                                   "Discarding ELS Request opcode %#x...\n",
-                                   purex->els_frame_payload[3]);
+                       purex_entry = (void *)pkt;
+                       switch (purex_entry->els_frame_payload[3]) {
+                       case ELS_RDP:
+                               pure_item = qla24xx_copy_std_pkt(vha, pkt);
+                               if (!pure_item)
+                                       break;
+                               qla24xx_queue_purex_item(vha, pure_item,
+                                                qla24xx_process_purex_rdp);
                                break;
-                       }
-                       pure_item = qla24xx_copy_std_pkt(vha, pkt);
-                       if (!pure_item)
+                       case ELS_FPIN:
+                               if (!vha->hw->flags.scm_enabled) {
+                                       ql_log(ql_log_warn, vha, 0x5094,
+                                              "SCM not active for this port\n");
+                                       break;
+                               }
+                               pure_item = qla27xx_copy_fpin_pkt(vha,
+                                                         (void **)&pkt, &rsp);
+                               if (!pure_item)
+                                       break;
+                               qla24xx_queue_purex_item(vha, pure_item,
+                                                qla27xx_process_purex_fpin);
                                break;
 
-                       qla24xx_queue_purex_item(vha, pure_item,
-                                                qla24xx_process_purex_rdp);
+                       default:
+                               ql_log(ql_log_warn, vha, 0x509c,
+                                      "Discarding ELS Request opcode 0x%x\n",
+                                      purex_entry->els_frame_payload[3]);
+                       }
                        break;
-               }
                default:
                        /* Type Not Supported. */
                        ql_dbg(ql_dbg_async, vha, 0x5042,
-                           "Received unknown response pkt type %x "
-                           "entry status=%x.\n",
-                           pkt->entry_type, pkt->entry_status);
+                              "Received unknown response pkt type 0x%x entry status=%x.\n",
+                              pkt->entry_type, pkt->entry_status);
                        break;
                }
                ((response_t *)pkt)->signature = RESPONSE_PROCESSED;
index b29d383..7388343 100644 (file)
@@ -1125,6 +1125,16 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
                            (ha->flags.secure_fw) ? "Supported" :
                            "Not Supported");
                }
+
+               if (ha->flags.scm_supported_a &&
+                   (ha->fw_attributes_ext[0] & FW_ATTR_EXT0_SCM_SUPPORTED)) {
+                       ha->flags.scm_supported_f = 1;
+                       memset(ha->sf_init_cb, 0, sizeof(struct init_sf_cb));
+                       ha->sf_init_cb->flags |= BIT_13;
+               }
+               ql_log(ql_log_info, vha, 0x11a3, "SCM in FW: %s\n",
+                      (ha->flags.scm_supported_f) ? "Supported" :
+                      "Not Supported");
        }
 
 failed:
@@ -1634,8 +1644,11 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
                mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10;
        if (IS_FWI2_CAPABLE(vha->hw))
                mcp->in_mb |= MBX_19|MBX_18|MBX_17|MBX_16;
-       if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
+       if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) {
                mcp->in_mb |= MBX_15;
+               mcp->out_mb |= MBX_7|MBX_21|MBX_22|MBX_23;
+       }
+
        mcp->tov = MBX_TOV_SECONDS;
        mcp->flags = 0;
        rval = qla2x00_mailbox_command(vha, mcp);
@@ -1688,8 +1701,22 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa,
                        }
                }
 
-               if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw))
+               if (IS_QLA27XX(vha->hw) || IS_QLA28XX(vha->hw)) {
                        vha->bbcr = mcp->mb[15];
+                       if (mcp->mb[7] & SCM_EDC_ACC_RECEIVED) {
+                               ql_log(ql_log_info, vha, 0x11a4,
+                                      "SCM: EDC ELS completed, flags 0x%x\n",
+                                      mcp->mb[21]);
+                       }
+                       if (mcp->mb[7] & SCM_RDF_ACC_RECEIVED) {
+                               vha->hw->flags.scm_enabled = 1;
+                               vha->scm_fabric_connection_flags |=
+                                   SCM_FLAG_RDF_COMPLETED;
+                               ql_log(ql_log_info, vha, 0x11a5,
+                                      "SCM: RDF ELS completed, flags 0x%x\n",
+                                      mcp->mb[23]);
+                       }
+               }
        }
 
        return rval;
@@ -1802,6 +1829,17 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
                mcp->mb[14] = sizeof(*ha->ex_init_cb);
                mcp->out_mb |= MBX_14|MBX_13|MBX_12|MBX_11|MBX_10;
        }
+
+       if (ha->flags.scm_supported_f) {
+               mcp->mb[1] |= BIT_1;
+               mcp->mb[16] = MSW(ha->sf_init_cb_dma);
+               mcp->mb[17] = LSW(ha->sf_init_cb_dma);
+               mcp->mb[18] = MSW(MSD(ha->sf_init_cb_dma));
+               mcp->mb[19] = LSW(MSD(ha->sf_init_cb_dma));
+               mcp->mb[15] = sizeof(*ha->sf_init_cb);
+               mcp->out_mb |= MBX_19|MBX_18|MBX_17|MBX_16|MBX_15;
+       }
+
        /* 1 and 2 should normally be captured. */
        mcp->in_mb = MBX_2|MBX_1|MBX_0;
        if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
index 80ce22c..9b59f03 100644 (file)
@@ -4218,6 +4218,16 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
                    "ex_init_cb=%p.\n", ha->ex_init_cb);
        }
 
+       /* Get consistent memory allocated for Special Features-CB. */
+       if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
+               ha->sf_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+                                               &ha->sf_init_cb_dma);
+               if (!ha->sf_init_cb)
+                       goto fail_sf_init_cb;
+               ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0199,
+                          "sf_init_cb=%p.\n", ha->sf_init_cb);
+       }
+
        INIT_LIST_HEAD(&ha->gbl_dsd_list);
 
        /* Get consistent memory allocated for Async Port-Database. */
@@ -4271,6 +4281,8 @@ fail_sfp_data:
 fail_loop_id_map:
        dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
 fail_async_pd:
+       dma_pool_free(ha->s_dma_pool, ha->sf_init_cb, ha->sf_init_cb_dma);
+fail_sf_init_cb:
        dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
 fail_ex_init_cb:
        kfree(ha->npiv_info);
@@ -4693,6 +4705,10 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        ha->ms_iocb = NULL;
        ha->ms_iocb_dma = 0;
 
+       if (ha->sf_init_cb)
+               dma_pool_free(ha->s_dma_pool,
+                             ha->sf_init_cb, ha->sf_init_cb_dma);
+
        if (ha->ex_init_cb)
                dma_pool_free(ha->s_dma_pool,
                        ha->ex_init_cb, ha->ex_init_cb_dma);
@@ -4780,6 +4796,8 @@ qla2x00_mem_free(struct qla_hw_data *ha)
        kfree(ha->swl);
        ha->swl = NULL;
        kfree(ha->loop_id_map);
+       ha->sf_init_cb = NULL;
+       ha->sf_init_cb_dma = 0;
        ha->loop_id_map = NULL;
 }