scsi: qla2xxx: Change in PUREX to handle FPIN ELS requests
authorShyam Sundar <ssundar@marvell.com>
Tue, 30 Jun 2020 10:22:28 +0000 (03:22 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 2 Jul 2020 02:24:16 +0000 (22:24 -0400)
SAN Congestion Management generates ELS pkts whose size can vary and be >
64 bytes. Change the PUREX handling code to support non-standard ELS pkt
size.

Link: https://lore.kernel.org/r/20200630102229.29660-2-njavali@marvell.com
Reviewed-by: Himanshu Madhani <himanshu.madhani@oracle.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_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c
include/uapi/scsi/fc/fc_els.h

index 42dbf90..9a0f231 100644 (file)
@@ -34,6 +34,8 @@
 #include <scsi/scsi_transport_fc.h>
 #include <scsi/scsi_bsg_fc.h>
 
+#include <uapi/scsi/fc/fc_els.h>
+
 /* Big endian Fibre Channel S_ID (source ID) or D_ID (destination ID). */
 typedef struct {
        uint8_t domain;
@@ -1304,7 +1306,6 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
 #define RNID_TYPE_ASIC_TEMP    0xC
 
 #define ELS_CMD_MAP_SIZE       32
-#define ELS_COMMAND_RDP                0x18
 
 /*
  * Firmware state codes from get firmware state mailbox command
@@ -4522,10 +4523,19 @@ struct active_regions {
 #define QLA_SET_DATA_RATE_NOLR 1
 #define QLA_SET_DATA_RATE_LR   2 /* Set speed and initiate LR */
 
+#define QLA_DEFAULT_PAYLOAD_SIZE       64
+/*
+ * This item might be allocated with a size > sizeof(struct purex_item).
+ * The "size" variable gives the size of the payload (which
+ * is variable) starting at "iocb".
+ */
 struct purex_item {
        struct list_head list;
        struct scsi_qla_host *vha;
-       void (*process_item)(struct scsi_qla_host *vha, void *pkt);
+       void (*process_item)(struct scsi_qla_host *vha,
+                            struct purex_item *pkt);
+       atomic_t in_use;
+       uint16_t size;
        struct {
                uint8_t iocb[64];
        } iocb;
@@ -4725,6 +4735,7 @@ typedef struct scsi_qla_host {
                struct list_head head;
                spinlock_t lock;
        } purex_list;
+       struct purex_item default_item;
 
        struct name_list_extended gnl;
        /* Count of active session/fcport */
index 061f91b..9cf33d0 100644 (file)
@@ -229,7 +229,8 @@ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *,
 int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *);
 int qla24xx_post_relogin_work(struct scsi_qla_host *vha);
 void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *);
-void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt);
+void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
+                              struct purex_item *pkt);
 
 /*
  * Global Functions in qla_mid.c source file.
index cf08005..3bbfff2 100644 (file)
@@ -31,35 +31,11 @@ const char *const port_state_str[] = {
        "ONLINE"
 };
 
-static void qla24xx_purex_iocb(scsi_qla_host_t *vha, void *pkt,
-       void (*process_item)(struct scsi_qla_host *vha, void *pkt))
-{
-       struct purex_list *list = &vha->purex_list;
-       struct purex_item *item;
-       ulong flags;
-
-       item = kzalloc(sizeof(*item), GFP_KERNEL);
-       if (!item) {
-               ql_log(ql_log_warn, vha, 0x5092,
-                   ">> Failed allocate purex list item.\n");
-               return;
-       }
-
-       item->vha = vha;
-       item->process_item = process_item;
-       memcpy(&item->iocb, pkt, sizeof(item->iocb));
-
-       spin_lock_irqsave(&list->lock, flags);
-       list_add_tail(&item->list, &list->head);
-       spin_unlock_irqrestore(&list->lock, flags);
-
-       set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
-}
-
 static void
-qla24xx_process_abts(struct scsi_qla_host *vha, void *pkt)
+qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
 {
-       struct abts_entry_24xx *abts = pkt;
+       struct abts_entry_24xx *abts =
+           (struct abts_entry_24xx *)&pkt->iocb;
        struct qla_hw_data *ha = vha->hw;
        struct els_entry_24xx *rsp_els;
        struct abts_entry_24xx *abts_rsp;
@@ -789,6 +765,74 @@ qla27xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
        }
 }
 
+struct purex_item *
+qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size)
+{
+       struct purex_item *item = NULL;
+       uint8_t item_hdr_size = sizeof(*item);
+
+       if (size > QLA_DEFAULT_PAYLOAD_SIZE) {
+               item = kzalloc(item_hdr_size +
+                   (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC);
+       } else {
+               if (atomic_inc_return(&vha->default_item.in_use) == 1) {
+                       item = &vha->default_item;
+                       goto initialize_purex_header;
+               } else {
+                       item = kzalloc(item_hdr_size, GFP_ATOMIC);
+               }
+       }
+       if (!item) {
+               ql_log(ql_log_warn, vha, 0x5092,
+                      ">> Failed allocate purex list item.\n");
+
+               return NULL;
+       }
+
+initialize_purex_header:
+       item->vha = vha;
+       item->size = size;
+       return item;
+}
+
+static void
+qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
+                        void (*process_item)(struct scsi_qla_host *vha,
+                                             struct purex_item *pkt))
+{
+       struct purex_list *list = &vha->purex_list;
+       ulong flags;
+
+       pkt->process_item = process_item;
+
+       spin_lock_irqsave(&list->lock, flags);
+       list_add_tail(&pkt->list, &list->head);
+       spin_unlock_irqrestore(&list->lock, flags);
+
+       set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
+}
+
+/**
+ * qla24xx_copy_std_pkt() - Copy over purex ELS which is
+ * contained in a single IOCB.
+ * purex packet.
+ * @vha: SCSI driver HA context
+ * @pkt: ELS packet
+ */
+struct purex_item
+*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
+{
+       struct purex_item *item;
+
+       item = qla24xx_alloc_purex_item(vha,
+                                       QLA_DEFAULT_PAYLOAD_SIZE);
+       if (!item)
+               return item;
+
+       memcpy(&item->iocb, pkt, sizeof(item->iocb));
+       return item;
+}
+
 /**
  * qla2x00_async_event() - Process aynchronous events.
  * @vha: SCSI driver HA context
@@ -3229,6 +3273,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_item *pure_item;
 
        if (!ha->flags.fw_started)
                return;
@@ -3280,8 +3325,12 @@ process_err:
                        break;
                case ABTS_RECV_24XX:
                        if (qla_ini_mode_enabled(vha)) {
-                               qla24xx_purex_iocb(vha, pkt,
-                                   qla24xx_process_abts);
+                               pure_item = qla24xx_copy_std_pkt(vha, pkt);
+                               if (!pure_item)
+                                       break;
+
+                               qla24xx_queue_purex_item(vha, pure_item,
+                                                        qla24xx_process_abts);
                                break;
                        }
                        if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
@@ -3332,13 +3381,18 @@ process_err:
                {
                        struct purex_entry_24xx *purex = (void *)pkt;
 
-                       if (purex->els_frame_payload[3] != ELS_COMMAND_RDP) {
+                       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]);
                                break;
                        }
-                       qla24xx_purex_iocb(vha, pkt, qla24xx_process_purex_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;
                }
                default:
index df31ee0..b29d383 100644 (file)
@@ -59,6 +59,7 @@ static struct rom_cmd {
        { MBC_IOCB_COMMAND_A64 },
        { MBC_GET_ADAPTER_LOOP_ID },
        { MBC_READ_SFP },
+       { MBC_SET_RNID_PARAMS },
        { MBC_GET_RNID_PARAMS },
        { MBC_GET_SET_ZIO_THRESHOLD },
 };
@@ -4866,6 +4867,7 @@ qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma,
        return rval;
 }
 
+#define PUREX_CMD_COUNT        2
 int
 qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
 {
@@ -4874,12 +4876,12 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
        mbx_cmd_t *mcp = &mc;
        uint8_t *els_cmd_map;
        dma_addr_t els_cmd_map_dma;
-       uint cmd_opcode = ELS_COMMAND_RDP;
-       uint index = cmd_opcode / 8;
-       uint bit = cmd_opcode % 8;
+       uint8_t cmd_opcode[PUREX_CMD_COUNT];
+       uint8_t i, index, purex_bit;
        struct qla_hw_data *ha = vha->hw;
 
-       if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) && !IS_QLA27XX(ha))
+       if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) &&
+           !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
                return QLA_SUCCESS;
 
        ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1197,
@@ -4893,7 +4895,17 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
                return QLA_MEMORY_ALLOC_FAILED;
        }
 
-       els_cmd_map[index] |= 1 << bit;
+       memset(els_cmd_map, 0, ELS_CMD_MAP_SIZE);
+
+       /* List of Purex ELS */
+       cmd_opcode[0] = ELS_FPIN;
+       cmd_opcode[1] = ELS_RDP;
+
+       for (i = 0; i < PUREX_CMD_COUNT; i++) {
+               index = cmd_opcode[i] / 8;
+               purex_bit = cmd_opcode[i] % 8;
+               els_cmd_map[index] |= 1 << purex_bit;
+       }
 
        mcp->mb[0] = MBC_SET_RNID_PARAMS;
        mcp->mb[1] = RNID_TYPE_ELS_CMD << 8;
index e92fad9..80ce22c 100644 (file)
@@ -5893,10 +5893,12 @@ qla25xx_rdp_port_speed_currently(struct qla_hw_data *ha)
  * vha:        SCSI qla host
  * purex: RDP request received by HBA
  */
-void qla24xx_process_purex_rdp(struct scsi_qla_host *vha, void *pkt)
+void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
+                              struct purex_item *item)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct purex_entry_24xx *purex = pkt;
+       struct purex_entry_24xx *purex =
+           (struct purex_entry_24xx *)&item->iocb;
        dma_addr_t rsp_els_dma;
        dma_addr_t rsp_payload_dma;
        dma_addr_t stat_dma;
@@ -6306,6 +6308,15 @@ dealloc:
                    rsp_els, rsp_els_dma);
 }
 
+void
+qla24xx_free_purex_item(struct purex_item *item)
+{
+       if (item == &item->vha->default_item)
+               memset(&item->vha->default_item, 0, sizeof(struct purex_item));
+       else
+               kfree(item);
+}
+
 void qla24xx_process_purex_list(struct purex_list *list)
 {
        struct list_head head = LIST_HEAD_INIT(head);
@@ -6318,8 +6329,8 @@ void qla24xx_process_purex_list(struct purex_list *list)
 
        list_for_each_entry_safe(item, next, &head, list) {
                list_del(&item->list);
-               item->process_item(item->vha, &item->iocb);
-               kfree(item);
+               item->process_item(item->vha, item);
+               qla24xx_free_purex_item(item);
        }
 }
 
index 66318c4..8c704e5 100644 (file)
@@ -41,6 +41,7 @@ enum fc_els_cmd {
        ELS_REC =       0x13,   /* read exchange concise */
        ELS_SRR =       0x14,   /* sequence retransmission request */
        ELS_FPIN =      0x16,   /* Fabric Performance Impact Notification */
+       ELS_RDP =       0x18,   /* Read Diagnostic Parameters */
        ELS_RDF =       0x19,   /* Register Diagnostic Functions */
        ELS_PRLI =      0x20,   /* process login */
        ELS_PRLO =      0x21,   /* process logout */
@@ -110,6 +111,7 @@ enum fc_els_cmd {
        [ELS_REC] =     "REC",                  \
        [ELS_SRR] =     "SRR",                  \
        [ELS_FPIN] =    "FPIN",                 \
+       [ELS_RDP] =     "RDP",                  \
        [ELS_RDF] =     "RDF",                  \
        [ELS_PRLI] =    "PRLI",                 \
        [ELS_PRLO] =    "PRLO",                 \