#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;
#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
#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;
struct list_head head;
spinlock_t lock;
} purex_list;
+ struct purex_item default_item;
struct name_list_extended gnl;
/* Count of active session/fcport */
"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;
}
}
+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
{
struct sts_entry_24xx *pkt;
struct qla_hw_data *ha = vha->hw;
+ struct purex_item *pure_item;
if (!ha->flags.fw_started)
return;
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) ||
{
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:
{ 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 },
};
return rval;
}
+#define PUREX_CMD_COUNT 2
int
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,
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;
* 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;
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);
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);
}
}