#include <linux/delay.h>
#include <linux/bsg-lib.h>
+static int qla28xx_validate_flash_image(struct bsg_job *bsg_job);
+
static void qla2xxx_free_fcport_work(struct work_struct *work)
{
struct fc_port *fcport = container_of(work, typeof(*fcport),
return 0;
}
+static int
+qla2x00_get_drv_attr(struct bsg_job *bsg_job)
+{
+ struct qla_drv_attr drv_attr;
+ struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+
+ memset(&drv_attr, 0, sizeof(struct qla_drv_attr));
+ drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT;
+
+
+ sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
+ bsg_job->reply_payload.sg_cnt, &drv_attr,
+ sizeof(struct qla_drv_attr));
+
+ bsg_reply->reply_payload_rcv_len = sizeof(struct qla_drv_attr);
+ bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_reply->result = DID_OK << 16;
+ bsg_job_done(bsg_job, bsg_reply->result, bsg_reply->reply_payload_rcv_len);
+
+ return 0;
+}
+
static int
qla2x00_manage_host_stats(struct bsg_job *bsg_job)
{
case QL_VND_GET_FLASH_UPDATE_CAPS:
return qla27xx_get_flash_upd_cap(bsg_job);
+ case QL_VND_GET_DRV_ATTR:
+ return qla2x00_get_drv_attr(bsg_job);
+
+ case QL_VND_IMG_SET_VALID:
+ return qla28xx_validate_flash_image(bsg_job);
+
case QL_VND_SET_FLASH_UPDATE_CAPS:
return qla27xx_set_flash_upd_cap(bsg_job);
return ret;
}
+
+static int
+qla28xx_do_validate_flash_image(struct bsg_job *bsg_job, uint16_t *state)
+{
+ struct fc_bsg_request *bsg_request = bsg_job->request;
+ scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
+ uint16_t mstate[16];
+ uint16_t mpi_state = 0;
+ uint16_t img_idx;
+ int rval = QLA_SUCCESS;
+
+ memset(mstate, 0, sizeof(mstate));
+
+ rval = qla2x00_get_firmware_state(vha, mstate);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "MBC to get MPI state failed (%d)\n", rval);
+ rval = -EINVAL;
+ goto exit_flash_img;
+ }
+
+ mpi_state = mstate[11];
+
+ if (!(mpi_state & BIT_9 && mpi_state & BIT_8 && mpi_state & BIT_15)) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "MPI firmware state failed (0x%02x)\n", mpi_state);
+ rval = -EINVAL;
+ goto exit_flash_img;
+ }
+
+ rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Unable to lock flash semaphore.");
+ goto exit_flash_img;
+ }
+
+ img_idx = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
+
+ rval = qla_mpipt_validate_fw(vha, img_idx, state);
+ if (rval != QLA_SUCCESS) {
+ ql_log(ql_log_warn, vha, 0xffff,
+ "Failed to validate Firmware image index [0x%x].\n",
+ img_idx);
+ }
+
+ qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
+
+exit_flash_img:
+ return rval;
+}
+
+static int qla28xx_validate_flash_image(struct bsg_job *bsg_job)
+{
+ scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
+ struct fc_bsg_reply *bsg_reply = bsg_job->reply;
+ struct qla_hw_data *ha = vha->hw;
+ uint16_t state = 0;
+ int rval = 0;
+
+ if (!IS_QLA28XX(ha) || vha->vp_idx != 0)
+ return -EPERM;
+
+ mutex_lock(&ha->optrom_mutex);
+ rval = qla28xx_do_validate_flash_image(bsg_job, &state);
+ if (rval)
+ rval = -EINVAL;
+ mutex_unlock(&ha->optrom_mutex);
+
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+
+ if (rval)
+ bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
+ (state == 39) ? EXT_STATUS_IMG_SET_VALID_ERR :
+ EXT_STATUS_IMG_SET_CONFIG_ERR;
+ else
+ bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = EXT_STATUS_OK;
+
+ bsg_reply->result = DID_OK << 16;
+ bsg_reply->reply_payload_rcv_len = 0;
+ bsg_job->reply_len = sizeof(struct fc_bsg_reply);
+ bsg_job_done(bsg_job, bsg_reply->result,
+ bsg_reply->reply_payload_rcv_len);
+
+ return QLA_SUCCESS;
+}
#define QL_VND_GET_PRIV_STATS_EX 0x1A
#define QL_VND_SS_GET_FLASH_IMAGE_STATUS 0x1E
#define QL_VND_EDIF_MGMT 0X1F
+#define QL_VND_GET_DRV_ATTR 0x22
#define QL_VND_MANAGE_HOST_STATS 0x23
#define QL_VND_GET_HOST_STATS 0x24
#define QL_VND_GET_TGT_STATS 0x25
#define QL_VND_MANAGE_HOST_PORT 0x26
#define QL_VND_MBX_PASSTHRU 0x2B
#define QL_VND_DPORT_DIAGNOSTICS_V2 0x2C
+#define QL_VND_IMG_SET_VALID 0x30
/* BSG Vendor specific subcode returns */
#define EXT_STATUS_OK 0
#define EXT_STATUS_BUFFER_TOO_SMALL 16
#define EXT_STATUS_NO_MEMORY 17
#define EXT_STATUS_DEVICE_OFFLINE 22
+#define EXT_STATUS_IMG_SET_VALID_ERR 47
+#define EXT_STATUS_IMG_SET_CONFIG_ERR 48
/*
* To support bidirectional iocb
uint8_t reserved[31];
} __packed;
+struct qla_drv_attr {
+ uint32_t attributes;
+ u32 ext_attributes;
+#define QLA_IMG_SET_VALID_SUPPORT BIT_4
+ u32 status_flags;
+ uint8_t reserved[20];
+} __packed;
+
#include "qla_edif_bsg.h"
#endif
return rval;
}
+
+int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, uint16_t *state)
+{
+ struct qla_hw_data *ha = vha->hw;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+ int rval;
+
+ if (!IS_QLA28XX(ha)) {
+ ql_dbg(ql_dbg_mbx, vha, 0xffff, "%s %d\n", __func__, __LINE__);
+ return QLA_FUNCTION_FAILED;
+ }
+
+ if (img_idx > 1) {
+ ql_log(ql_log_info, vha, 0xffff,
+ "%s %d Invalid flash image index [%d]\n",
+ __func__, __LINE__, img_idx);
+ return QLA_INVALID_COMMAND;
+ }
+
+ memset(&mc, 0, sizeof(mc));
+ mcp->mb[0] = MBC_MPI_PASSTHROUGH;
+ mcp->mb[1] = MPIPT_SUBCMD_VALIDATE_FW;
+ mcp->mb[2] = img_idx;
+ mcp->out_mb = MBX_1|MBX_0;
+ mcp->in_mb = MBX_2|MBX_1|MBX_0;
+
+ /* send mb via iocb */
+ rval = qla24xx_send_mb_cmd(vha, &mc);
+ if (rval) {
+ ql_log(ql_log_info, vha, 0xffff, "%s:Failed %x (mb=%x,%x)\n",
+ __func__, rval, mcp->mb[0], mcp->mb[1]);
+ *state = mcp->mb[1];
+ } else {
+ ql_log(ql_log_info, vha, 0xffff, "%s: mb=%x,%x,%x\n", __func__,
+ mcp->mb[0], mcp->mb[1], mcp->mb[2]);
+ }
+
+ return rval;
+}