mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-08-30 15:43:08 -04:00
Merge patch series "scsi: qla2xxx: Add QLA29xx series adapter support"
Nilesh Javali <njavali@marvell.com> says: Add support for the QLA29xx generation of Marvell QLogic Fibre Channel HBAs (ISP2091/ISP2291/ISP2099/ISP2299). The 29xx family shares much of its architecture with the existing 27xx/28xx adapters but introduces 128-byte request and response ring entries (up from 64 bytes), requiring extended IOCB definitions and updated ring management throughout the driver. The key hardware change is the wider IOCB format: every request and response queue entry is now 128 bytes. This propagates into every code path that builds, submits, or processes IOCBs -- command submission, status completion, marker, CT pass-through, ELS, logio, task management, abort, ABTS, VP control, and NVMe. The series is organised as follows: Patches 01-08: Foundation and flash/firmware infrastructure PCI device ID registration, ISP-flags wiring, flash read/write interface, NVRAM configuration, queue initialisation, FC operational firmware load, removal of a redundant VPD flash read in the sysfs read path, and BSG passthrough (flash block I/O, MPI firmware load/dump). Patches 09-11: 128-byte IOCB infrastructure New qla_fw29.h header with extended structure definitions, status continuation and marker IOCBs, and IO-path updates that select the correct IOCB size via the entry-size helpers. Patches 12-24: Sysfs, mailbox commands, and core enablement Sysfs attribute gating for unsupported 29xx features, mailbox command enablement (get_fw_version, execute_fw, get_adapter_id, init_firmware, get_firmware_state, serdes, ELS, echo_test, data rate), shutdown path, ring-slot helpers, and memory allocation updates. Patches 25-39: Response-path IOCB handling and final wiring Status continuation, status entry, CT pass-through, PUREX, ELS, logio, task management, abort, ABTS, VP control/config/report-ID, LS4 pass-through, and BSG feature gating adjustments. Patches 40-55: bug fixes uncovered during review of the earlier postings -- queue teardown NULL dma_free and bitmap locking, endianness/bitfield cleanups, 64-bit FPM word counters, 64G/128G port speed setting and reporting, an edif NULL deref, Name Server logout detection on FWI2 adapters, VP index bounds, NVMe abort and LS-reject locking, a dport diagnostics info leak, a BSG job leak, and an unbounded FRU image count. Patch 56: bump the driver version to 12.00.00.2607b1. The series applies on top of Linux 7.2-rc1. Thanks, Nilesh [mkp: Resolve merge conflict] Link: https://patch.msgid.link/20260723050413.3897522-1-njavali@marvell.com Signed-off-by: Martin K. Petersen (Oracle) <mkp@kernel.org>
This commit is contained in:
@@ -580,7 +580,6 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
|
||||
ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
|
||||
ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
|
||||
skip:
|
||||
return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
|
||||
}
|
||||
@@ -1472,6 +1471,9 @@ qla2x00_optrom_gold_fw_version_show(struct device *dev,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
@@ -1500,6 +1502,9 @@ qla24xx_84xx_fw_version_show(struct device *dev,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
if (!IS_QLA84XX(ha))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
@@ -1521,7 +1526,7 @@ qla2x00_serdes_version_show(struct device *dev, struct device_attribute *attr,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
|
||||
@@ -1537,7 +1542,7 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
|
||||
@@ -1566,6 +1571,9 @@ qla2x00_flash_block_size_show(struct device *dev,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size);
|
||||
}
|
||||
|
||||
@@ -1574,6 +1582,10 @@ qla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
if (!IS_CNA_CAPABLE(vha->hw))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
@@ -1586,6 +1598,10 @@ qla2x00_vn_port_mac_address_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
if (!IS_CNA_CAPABLE(vha->hw))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
@@ -1717,6 +1733,10 @@ qla2x00_allow_cna_fw_dump_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
if (!IS_P3P_TYPE(vha->hw))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
@@ -1750,7 +1770,7 @@ qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
|
||||
@@ -1764,10 +1784,11 @@ qla2x00_min_supported_speed_show(struct device *dev,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n",
|
||||
ha->min_supported_speed == 7 ? "128Gps" :
|
||||
ha->min_supported_speed == 6 ? "64Gps" :
|
||||
ha->min_supported_speed == 5 ? "32Gps" :
|
||||
ha->min_supported_speed == 4 ? "16Gps" :
|
||||
@@ -1783,10 +1804,11 @@ qla2x00_max_supported_speed_show(struct device *dev,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n",
|
||||
ha->max_supported_speed == 3 ? "128Gps" :
|
||||
ha->max_supported_speed == 2 ? "64Gps" :
|
||||
ha->max_supported_speed == 1 ? "32Gps" :
|
||||
ha->max_supported_speed == 0 ? "16Gps" : "unknown");
|
||||
@@ -1802,7 +1824,7 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
|
||||
int mode = QLA_SET_DATA_RATE_LR;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) {
|
||||
ql_log(ql_log_warn, vha, 0x70d8,
|
||||
"Speed setting not supported \n");
|
||||
return -EINVAL;
|
||||
@@ -1813,7 +1835,7 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
|
||||
return rval;
|
||||
speed = type;
|
||||
if (type == 40 || type == 80 || type == 160 ||
|
||||
type == 320) {
|
||||
type == 320 || type == 640 || type == 1280) {
|
||||
ql_dbg(ql_dbg_user, vha, 0x70d9,
|
||||
"Setting will be affected after a loss of sync\n");
|
||||
type = type/10;
|
||||
@@ -1838,6 +1860,12 @@ qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
|
||||
case 32:
|
||||
ha->set_data_rate = PORT_SPEED_32GB;
|
||||
break;
|
||||
case 64:
|
||||
ha->set_data_rate = PORT_SPEED_64GB;
|
||||
break;
|
||||
case 128:
|
||||
ha->set_data_rate = PORT_SPEED_128GB;
|
||||
break;
|
||||
default:
|
||||
ql_log(ql_log_warn, vha, 0x1199,
|
||||
"Unrecognized speed setting:%lx. Setting Autoneg\n",
|
||||
@@ -1867,6 +1895,7 @@ static const struct {
|
||||
{ PORT_SPEED_16GB, "16" },
|
||||
{ PORT_SPEED_32GB, "32" },
|
||||
{ PORT_SPEED_64GB, "64" },
|
||||
{ PORT_SPEED_128GB, "128" },
|
||||
{ PORT_SPEED_10GB, "10" },
|
||||
};
|
||||
|
||||
@@ -2366,7 +2395,7 @@ qla2x00_fw_attr_show(struct device *dev,
|
||||
scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return scnprintf(buf, PAGE_SIZE, "\n");
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%llx\n",
|
||||
@@ -2413,7 +2442,7 @@ qla2x00_mpi_fw_state_show(struct device *dev, struct device_attribute *attr,
|
||||
u16 mpi_state;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha)))
|
||||
if (!(IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)))
|
||||
return scnprintf(buf, PAGE_SIZE,
|
||||
"MPI state reporting is not supported for this HBA.\n");
|
||||
|
||||
@@ -2648,6 +2677,9 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
|
||||
case PORT_SPEED_64GB:
|
||||
speed = FC_PORTSPEED_64GBIT;
|
||||
break;
|
||||
case PORT_SPEED_128GB:
|
||||
speed = FC_PORTSPEED_128GBIT;
|
||||
break;
|
||||
default:
|
||||
speed = FC_PORTSPEED_UNKNOWN;
|
||||
break;
|
||||
@@ -2964,7 +2996,8 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
|
||||
p->error_frames =
|
||||
le32_to_cpu(stats->dropped_frames) +
|
||||
le32_to_cpu(stats->discarded_frames);
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha)) {
|
||||
p->rx_words = le64_to_cpu(stats->fpm_recv_word_cnt);
|
||||
p->tx_words = le64_to_cpu(stats->fpm_xmit_word_cnt);
|
||||
} else {
|
||||
@@ -3409,6 +3442,8 @@ qla2x00_get_host_supported_speeds(scsi_qla_host_t *vha, uint speeds)
|
||||
{
|
||||
uint supported_speeds = FC_PORTSPEED_UNKNOWN;
|
||||
|
||||
if (speeds & FDMI_PORT_SPEED_128GB)
|
||||
supported_speeds |= FC_PORTSPEED_128GBIT;
|
||||
if (speeds & FDMI_PORT_SPEED_64GB)
|
||||
supported_speeds |= FC_PORTSPEED_64GBIT;
|
||||
if (speeds & FDMI_PORT_SPEED_32GB)
|
||||
|
||||
@@ -1407,23 +1407,14 @@ qla24xx_iidma(struct bsg_job *bsg_job)
|
||||
|
||||
static int
|
||||
qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
uint8_t is_update)
|
||||
uint32_t start, uint8_t is_update)
|
||||
{
|
||||
struct fc_bsg_request *bsg_request = bsg_job->request;
|
||||
uint32_t start = 0;
|
||||
int valid = 0;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (unlikely(pci_channel_offline(ha->pdev)))
|
||||
return -EINVAL;
|
||||
|
||||
start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
if (start > ha->optrom_size) {
|
||||
ql_log(ql_log_warn, vha, 0x7055,
|
||||
"start %d > optrom_size %d.\n", start, ha->optrom_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ha->optrom_state != QLA_SWAITING) {
|
||||
ql_log(ql_log_info, vha, 0x7056,
|
||||
"optrom_state %d.\n", ha->optrom_state);
|
||||
@@ -1431,42 +1422,79 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
}
|
||||
|
||||
ha->optrom_region_start = start;
|
||||
ql_dbg(ql_dbg_user, vha, 0x7057, "is_update=%d.\n", is_update);
|
||||
if (is_update) {
|
||||
if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
|
||||
valid = 1;
|
||||
else if (start == (ha->flt_region_boot * 4) ||
|
||||
start == (ha->flt_region_fw * 4))
|
||||
valid = 1;
|
||||
else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
|
||||
IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha))
|
||||
valid = 1;
|
||||
if (!valid) {
|
||||
ql_log(ql_log_warn, vha, 0x7058,
|
||||
"Invalid start region 0x%x/0x%x.\n", start,
|
||||
bsg_job->request_payload.payload_len);
|
||||
|
||||
if (IS_QLA29XX(ha)) {
|
||||
if (start > ha->optrom_size) {
|
||||
ql_log(ql_log_warn, vha, 0x7055,
|
||||
"start %d > optrom_size %d.\n", start,
|
||||
ha->optrom_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->request_payload.payload_len > ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->request_payload.payload_len;
|
||||
ha->optrom_state = QLA_SWRITING;
|
||||
if (is_update) {
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->request_payload.payload_len >
|
||||
ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->request_payload.payload_len;
|
||||
ha->optrom_state = QLA_SWRITING;
|
||||
} else {
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->reply_payload.payload_len >
|
||||
ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->reply_payload.payload_len;
|
||||
ha->optrom_state = QLA_SREADING;
|
||||
}
|
||||
} else {
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->reply_payload.payload_len > ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->reply_payload.payload_len;
|
||||
ha->optrom_state = QLA_SREADING;
|
||||
if (start > ha->optrom_size) {
|
||||
ql_log(ql_log_warn, vha, 0x7055,
|
||||
"start %d > optrom_size %d.\n", start,
|
||||
ha->optrom_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_user, vha, 0x7057,
|
||||
"is_update=%d.\n", is_update);
|
||||
if (is_update) {
|
||||
if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
|
||||
valid = 1;
|
||||
else if (start == (ha->flt_region_boot * 4) ||
|
||||
start == (ha->flt_region_fw * 4))
|
||||
valid = 1;
|
||||
else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
|
||||
IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) ||
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
valid = 1;
|
||||
if (!valid) {
|
||||
ql_log(ql_log_warn, vha, 0x7058,
|
||||
"Invalid start region 0x%x/0x%x.\n",
|
||||
start,
|
||||
bsg_job->request_payload.payload_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->request_payload.payload_len >
|
||||
ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->request_payload.payload_len;
|
||||
ha->optrom_state = QLA_SWRITING;
|
||||
} else {
|
||||
ha->optrom_region_size = start +
|
||||
bsg_job->reply_payload.payload_len >
|
||||
ha->optrom_size ?
|
||||
ha->optrom_size - start :
|
||||
bsg_job->reply_payload.payload_len;
|
||||
ha->optrom_state = QLA_SREADING;
|
||||
}
|
||||
}
|
||||
|
||||
ha->optrom_buffer = vzalloc(ha->optrom_region_size);
|
||||
if (!ha->optrom_buffer) {
|
||||
ql_log(ql_log_warn, vha, 0x7059,
|
||||
"Read: Unable to allocate memory for optrom retrieval "
|
||||
"(%x)\n", ha->optrom_region_size);
|
||||
"%s: Unable to allocate memory for optrom retrieval (%x)\n",
|
||||
__func__, ha->optrom_region_size);
|
||||
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
return -ENOMEM;
|
||||
@@ -1478,17 +1506,25 @@ qla2x00_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
static int
|
||||
qla2x00_read_optrom(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_request = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
int rval = 0;
|
||||
|
||||
if (ha->flags.nic_core_reset_hdlr_active)
|
||||
return -EBUSY;
|
||||
|
||||
if (IS_QLA29XX(ha)) {
|
||||
ql_log(ql_log_warn, vha, 0x7070,
|
||||
"Legacy optrom read not supported on 29xx.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, 0);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, start, 0);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
@@ -1515,14 +1551,16 @@ qla2x00_read_optrom(struct bsg_job *bsg_job)
|
||||
static int
|
||||
qla2x00_update_optrom(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_request = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint32_t start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
int rval = 0;
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, 1);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, start, 1);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
@@ -1554,6 +1592,379 @@ qla2x00_update_optrom(struct bsg_job *bsg_job)
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_bsg_flash_block_read - Read flash block for QLA29XX.
|
||||
* @bsg_job: BSG job structure.
|
||||
*
|
||||
* Returns 0 on success, error code on failure.
|
||||
*/
|
||||
static int qla29xx_bsg_flash_block_read(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_req = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_block_rw *brcmd;
|
||||
void *buf;
|
||||
uint16_t opts = 0;
|
||||
int rval = 0;
|
||||
|
||||
if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
|
||||
2 * sizeof(uint32_t) + sizeof(struct qla_block_rw))
|
||||
return -EINVAL;
|
||||
|
||||
brcmd =
|
||||
(struct qla_block_rw *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
|
||||
|
||||
ql_log(ql_log_info, vha, 0x7062,
|
||||
"%s: region 0x%x options 0x%x rw_length 0x%x offset 0x%x chunk_length 0x%x\n",
|
||||
__func__, brcmd->region, brcmd->options, brcmd->rw_length,
|
||||
brcmd->region_offset, brcmd->chunk_length);
|
||||
|
||||
if (brcmd->region > U16_MAX) {
|
||||
ql_log(ql_log_warn, vha, 0x7066,
|
||||
"%s: invalid region 0x%x\n", __func__, brcmd->region);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, brcmd->region_offset, 0);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
}
|
||||
|
||||
check_and_set_mbc_bits(brcmd->options, opts, QLA_IS_TIM, BIT_15);
|
||||
check_and_set_mbc_bits(brcmd->options, opts, QLA_IS_SECURE, BIT_7);
|
||||
check_and_set_mbc_bits(brcmd->options, opts, QLA_UPDATE_MBR, BIT_8);
|
||||
|
||||
if (!ha->isp_ops->read_optrom_region) {
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf = ha->isp_ops->read_optrom_region(vha, brcmd->region, opts,
|
||||
ha->optrom_buffer, ha->optrom_region_start,
|
||||
ha->optrom_region_size);
|
||||
if (!buf) {
|
||||
ql_log(ql_log_warn, vha, 0x7063,
|
||||
"%s failed to read flash region 0x%x\n",
|
||||
__func__, brcmd->region);
|
||||
bsg_reply->result = -EINVAL;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_MAILBOX;
|
||||
bsg_reply->reply_payload_rcv_len = 0;
|
||||
} else {
|
||||
bsg_reply->result = DID_OK;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_OK;
|
||||
|
||||
ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x72a6,
|
||||
ha->optrom_buffer, ha->optrom_region_size);
|
||||
|
||||
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
|
||||
bsg_job->reply_payload.sg_cnt,
|
||||
ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
|
||||
bsg_reply->reply_payload_rcv_len = ha->optrom_region_size;
|
||||
}
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_bsg_flash_block_write - Write flash block for QLA29XX.
|
||||
* @bsg_job: BSG job structure.
|
||||
*
|
||||
* Returns 0 on success, error code on failure.
|
||||
*/
|
||||
static int qla29xx_bsg_flash_block_write(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_req = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_block_rw *bwcmd;
|
||||
uint16_t opts = 0;
|
||||
int rval = 0;
|
||||
|
||||
if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
|
||||
2 * sizeof(uint32_t) + sizeof(struct qla_block_rw))
|
||||
return -EINVAL;
|
||||
|
||||
bwcmd =
|
||||
(struct qla_block_rw *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
|
||||
|
||||
ql_log(ql_log_info, vha, 0x7064,
|
||||
"%s: region 0x%x options 0x%x rw_length 0x%x offset 0x%x chunk_length 0x%x\n",
|
||||
__func__, bwcmd->region, bwcmd->options, bwcmd->rw_length,
|
||||
bwcmd->region_offset, bwcmd->chunk_length);
|
||||
|
||||
if (bwcmd->region > U16_MAX) {
|
||||
ql_log(ql_log_warn, vha, 0x7067,
|
||||
"%s: invalid region 0x%x\n", __func__, bwcmd->region);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla2x00_optrom_setup(bsg_job, vha, bwcmd->region_offset, 1);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
}
|
||||
|
||||
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
|
||||
bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
|
||||
ql_dump_buffer(ql_dbg_user + ql_dbg_verbose, vha, 0x73a6,
|
||||
ha->optrom_buffer, ha->optrom_region_size);
|
||||
|
||||
check_and_set_mbc_bits(bwcmd->options, opts, QLA_IS_TIM, BIT_15);
|
||||
check_and_set_mbc_bits(bwcmd->options, opts, QLA_IS_SECURE, BIT_7);
|
||||
check_and_set_mbc_bits(bwcmd->options, opts, QLA_UPDATE_MBR, BIT_8);
|
||||
|
||||
if (!ha->isp_ops->write_optrom_region) {
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rval = ha->isp_ops->write_optrom_region(vha, bwcmd->region, opts,
|
||||
ha->optrom_buffer, ha->optrom_region_start,
|
||||
ha->optrom_region_size);
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x7065,
|
||||
"%s failed to write flash %x\n", __func__, rval);
|
||||
bsg_reply->result = -EINVAL;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_MAILBOX;
|
||||
} else {
|
||||
bsg_reply->result = DID_OK;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_OK;
|
||||
}
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qla29xx_mpi_optrom_setup(struct bsg_job *bsg_job, scsi_qla_host_t *vha,
|
||||
uint32_t start, uint8_t is_update)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (unlikely(pci_channel_offline(ha->pdev)))
|
||||
return -EINVAL;
|
||||
|
||||
if (ha->optrom_state != QLA_SWAITING) {
|
||||
ql_log(ql_log_info, vha, 0x7068,
|
||||
"optrom_state %d.\n", ha->optrom_state);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ha->optrom_region_start = start;
|
||||
if (is_update) {
|
||||
ha->optrom_region_size = bsg_job->request_payload.payload_len;
|
||||
ha->optrom_state = QLA_SWRITING;
|
||||
} else {
|
||||
ha->optrom_region_size = bsg_job->reply_payload.payload_len;
|
||||
ha->optrom_state = QLA_SREADING;
|
||||
}
|
||||
|
||||
ha->optrom_buffer = vzalloc(ha->optrom_region_size);
|
||||
if (!ha->optrom_buffer) {
|
||||
ql_log(ql_log_warn, vha, 0x7069,
|
||||
"%s: Unable to allocate memory for optrom retrieval (%x)\n",
|
||||
__func__, ha->optrom_region_size);
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qla2900_bsg_dump_mpi(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_req = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_load_dump_mpi *dmcmd;
|
||||
uint16_t opts = 0;
|
||||
int rval = 0;
|
||||
|
||||
if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
|
||||
2 * sizeof(uint32_t) + sizeof(struct qla_load_dump_mpi))
|
||||
return -EINVAL;
|
||||
|
||||
if (!IS_QLA29XX(ha)) {
|
||||
ql_log(ql_log_warn, vha, 0x706c,
|
||||
"%s: MPI dump not supported on this adapter.\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dmcmd =
|
||||
(struct qla_load_dump_mpi *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
|
||||
|
||||
ql_log(ql_log_info, vha, 0xffff,
|
||||
"%s: mpi_address 0x%x mpi options 0x%x length 0x%x\n",
|
||||
__func__, dmcmd->mpi_address, dmcmd->options, dmcmd->length);
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla29xx_mpi_optrom_setup(bsg_job, vha, dmcmd->mpi_address, 1);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
}
|
||||
|
||||
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
|
||||
bsg_job->request_payload.sg_cnt, ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
|
||||
ql_dump_buffer(ql_dbg_init, vha, 0x00d7, ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
|
||||
check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_SECURE_ENABLE,
|
||||
BIT_3);
|
||||
check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_OTP_PROV, BIT_4);
|
||||
check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_DEV_CSR, BIT_5);
|
||||
check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_AUTH_CMD_BIN,
|
||||
BIT_6);
|
||||
check_and_set_mbc_bits(dmcmd->options, opts, QLA_LDM_MLDSA_ALGO,
|
||||
BIT_9);
|
||||
|
||||
rval = qla29xx_mpi_optrom_data(vha, opts, ha->optrom_buffer,
|
||||
ha->optrom_region_start,
|
||||
ha->optrom_region_size,
|
||||
QLA29XX_MPI_OP_DUMP);
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0xffff,
|
||||
"%s failed mpi dump %x\n", __func__, rval);
|
||||
bsg_reply->result = -EINVAL;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_MAILBOX;
|
||||
} else {
|
||||
bsg_reply->result = DID_OK;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_OK;
|
||||
}
|
||||
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qla2900_bsg_load_mpi(struct bsg_job *bsg_job)
|
||||
{
|
||||
struct fc_bsg_request *bsg_req = bsg_job->request;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct Scsi_Host *host = fc_bsg_to_shost(bsg_job);
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_load_dump_mpi *lmcmd;
|
||||
uint16_t opts = 0;
|
||||
int rval = 0;
|
||||
|
||||
if (bsg_job->request_len < sizeof(struct fc_bsg_request) +
|
||||
2 * sizeof(uint32_t) + sizeof(struct qla_load_dump_mpi))
|
||||
return -EINVAL;
|
||||
|
||||
if (!IS_QLA29XX(ha)) {
|
||||
ql_log(ql_log_warn, vha, 0x706d,
|
||||
"%s: MPI load not supported on this adapter.\n",
|
||||
__func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
lmcmd =
|
||||
(struct qla_load_dump_mpi *)&bsg_req->rqst_data.h_vendor.vendor_cmd[2];
|
||||
|
||||
ql_log(ql_log_info, vha, 0xffff,
|
||||
"%s: mpi_address 0x%x mpi options 0x%x length 0x%x\n",
|
||||
__func__, lmcmd->mpi_address, lmcmd->options, lmcmd->length);
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla29xx_mpi_optrom_setup(bsg_job, vha, lmcmd->mpi_address, 0);
|
||||
if (rval) {
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
return rval;
|
||||
}
|
||||
|
||||
check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_SECURE_ENABLE,
|
||||
BIT_3);
|
||||
check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_DEV_CSR, BIT_5);
|
||||
check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_SHADOW_REGS,
|
||||
BIT_7);
|
||||
check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_CA_CSR, BIT_8);
|
||||
check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_MLDSA_ALGO,
|
||||
BIT_9);
|
||||
check_and_set_mbc_bits(lmcmd->options, opts, QLA_LDM_MLDSA_SIGNATURE,
|
||||
BIT_10);
|
||||
|
||||
rval = qla29xx_mpi_optrom_data(vha, opts, ha->optrom_buffer,
|
||||
ha->optrom_region_start,
|
||||
ha->optrom_region_size,
|
||||
QLA29XX_MPI_OP_LOAD);
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0xffff,
|
||||
"%s failed mpi load %x\n", __func__, rval);
|
||||
bsg_reply->result = -EINVAL;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_MAILBOX;
|
||||
} else {
|
||||
bsg_reply->result = DID_OK;
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_OK;
|
||||
}
|
||||
|
||||
ql_dump_buffer(ql_dbg_init, vha, 0x00d7, ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
|
||||
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
|
||||
bsg_job->reply_payload.sg_cnt,
|
||||
ha->optrom_buffer,
|
||||
ha->optrom_region_size);
|
||||
|
||||
bsg_reply->reply_payload_rcv_len = ha->optrom_region_size;
|
||||
vfree(ha->optrom_buffer);
|
||||
ha->optrom_buffer = NULL;
|
||||
ha->optrom_state = QLA_SWAITING;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qla2x00_update_fru_versions(struct bsg_job *bsg_job)
|
||||
{
|
||||
@@ -1580,6 +1991,13 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job)
|
||||
|
||||
image = list->version;
|
||||
count = list->count;
|
||||
|
||||
if (struct_size(list, version, count) > sizeof(bsg)) {
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_INVALID_PARAM;
|
||||
goto dealloc;
|
||||
}
|
||||
|
||||
while (count--) {
|
||||
memcpy(sfp, &image->field_info, sizeof(image->field_info));
|
||||
rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
|
||||
@@ -2195,7 +2613,7 @@ qla27xx_get_flash_upd_cap(struct bsg_job *bsg_job)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flash_update_caps cap;
|
||||
|
||||
if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha))
|
||||
if (!(IS_QLA27XX(ha)) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
@@ -2228,7 +2646,7 @@ qla27xx_set_flash_upd_cap(struct bsg_job *bsg_job)
|
||||
uint64_t online_fw_attr = 0;
|
||||
struct qla_flash_update_caps cap;
|
||||
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
memset(&cap, 0, sizeof(cap));
|
||||
@@ -2276,7 +2694,7 @@ qla27xx_get_bbcr_data(struct bsg_job *bsg_job)
|
||||
uint8_t domain, area, al_pa, state;
|
||||
int rval;
|
||||
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
memset(&bbcr, 0, sizeof(bbcr));
|
||||
@@ -2392,10 +2810,10 @@ qla2x00_do_dport_diagnostics(struct bsg_job *bsg_job)
|
||||
struct qla_dport_diag *dd;
|
||||
|
||||
if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
|
||||
!IS_QLA28XX(vha->hw))
|
||||
!IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
|
||||
return -EPERM;
|
||||
|
||||
dd = kmalloc_obj(*dd);
|
||||
dd = kzalloc_obj(*dd);
|
||||
if (!dd) {
|
||||
ql_log(ql_log_warn, vha, 0x70db,
|
||||
"Failed to allocate memory for dport.\n");
|
||||
@@ -2518,8 +2936,13 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
|
||||
struct qla_active_regions regions = { };
|
||||
struct active_regions active_regions = { };
|
||||
|
||||
qla27xx_get_active_image(vha, &active_regions);
|
||||
regions.global_image = active_regions.global;
|
||||
if (IS_QLA29XX(ha))
|
||||
return -EPERM;
|
||||
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
qla27xx_get_active_image(vha, &active_regions);
|
||||
regions.global_image = active_regions.global;
|
||||
}
|
||||
|
||||
if (IS_QLA27XX(ha))
|
||||
regions.nvme_params = QLA27XX_PRIMARY_IMAGE;
|
||||
@@ -2555,11 +2978,14 @@ qla2x00_get_flash_image_status(struct bsg_job *bsg_job)
|
||||
static int
|
||||
qla2x00_get_drv_attr(struct bsg_job *bsg_job)
|
||||
{
|
||||
scsi_qla_host_t *vha = shost_priv(fc_bsg_to_shost(bsg_job));
|
||||
struct qla_drv_attr drv_attr;
|
||||
struct fc_bsg_reply *bsg_reply = bsg_job->reply;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
memset(&drv_attr, 0, sizeof(struct qla_drv_attr));
|
||||
drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT;
|
||||
if (!IS_QLA29XX(ha))
|
||||
drv_attr.ext_attributes |= QLA_IMG_SET_VALID_SUPPORT;
|
||||
|
||||
|
||||
sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
|
||||
@@ -3007,6 +3433,18 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j
|
||||
case QL_VND_MBX_PASSTHRU:
|
||||
return qla2x00_mailbox_passthru(bsg_job);
|
||||
|
||||
case QL_VND_READ_FLASH_BLOCK:
|
||||
return qla29xx_bsg_flash_block_read(bsg_job);
|
||||
|
||||
case QL_VND_WRITE_FLASH_BLOCK:
|
||||
return qla29xx_bsg_flash_block_write(bsg_job);
|
||||
|
||||
case QL_VND_LOAD_MPI:
|
||||
return qla2900_bsg_load_mpi(bsg_job);
|
||||
|
||||
case QL_VND_DUMP_MPI:
|
||||
return qla2900_bsg_dump_mpi(bsg_job);
|
||||
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
@@ -3365,9 +3803,8 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job)
|
||||
bsg_reply->result = DID_OK << 16;
|
||||
bsg_reply->reply_payload_rcv_len = 0;
|
||||
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
|
||||
if (!rval)
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
#define QL_VND_MBX_PASSTHRU 0x2B
|
||||
#define QL_VND_DPORT_DIAGNOSTICS_V2 0x2C
|
||||
#define QL_VND_IMG_SET_VALID 0x30
|
||||
#define QL_VND_READ_FLASH_BLOCK 0x33
|
||||
#define QL_VND_WRITE_FLASH_BLOCK 0x34
|
||||
#define QL_VND_LOAD_MPI 0x35
|
||||
#define QL_VND_DUMP_MPI 0x36
|
||||
|
||||
/* BSG Vendor specific subcode returns */
|
||||
#define EXT_STATUS_OK 0
|
||||
@@ -83,6 +87,36 @@
|
||||
#define ELS_OPCODE_BYTE 0x10
|
||||
|
||||
/* BSG Vendor specific definations */
|
||||
|
||||
#define QLA_IS_TIM 0x1
|
||||
#define QLA_IS_SECURE 0x2
|
||||
#define QLA_UPDATE_MBR 0x4
|
||||
|
||||
struct qla_block_rw {
|
||||
uint32_t region;
|
||||
uint32_t rw_length;
|
||||
uint32_t options;
|
||||
uint32_t region_offset;
|
||||
uint32_t chunk_length;
|
||||
uint8_t reserved[44];
|
||||
} __packed;
|
||||
|
||||
struct qla_load_dump_mpi {
|
||||
uint32_t mpi_address;
|
||||
uint32_t length;
|
||||
uint32_t options;
|
||||
#define QLA_LDM_SECURE_ENABLE 0x1
|
||||
#define QLA_LDM_OTP_PROV 0x2
|
||||
#define QLA_LDM_DEV_CSR 0x4
|
||||
#define QLA_LDM_AUTH_CMD_BIN 0x8
|
||||
#define QLA_LDM_SHADOW_REGS 0x10
|
||||
#define QLA_LDM_CA_CSR 0x20
|
||||
#define QLA_LDM_MLDSA_ALGO 0x40
|
||||
#define QLA_LDM_MLDSA_SIGNATURE 0x80
|
||||
|
||||
uint8_t reserved[52];
|
||||
} __packed;
|
||||
|
||||
#define A84_ISSUE_WRITE_TYPE_CMD 0
|
||||
#define A84_ISSUE_READ_TYPE_CMD 1
|
||||
#define A84_CLEANUP_CMD 2
|
||||
|
||||
@@ -89,16 +89,17 @@ qla2xxx_copy_queues(struct qla_hw_data *ha, void *ptr)
|
||||
{
|
||||
struct req_que *req = ha->req_q_map[0];
|
||||
struct rsp_que *rsp = ha->rsp_q_map[0];
|
||||
size_t req_entry_size = qla_req_entry_size(ha);
|
||||
size_t rsp_entry_size = qla_rsp_entry_size(ha);
|
||||
|
||||
/* Request queue. */
|
||||
memcpy(ptr, req->ring, req->length *
|
||||
sizeof(request_t));
|
||||
memcpy(ptr, req->ring, req->length * req_entry_size);
|
||||
|
||||
/* Response queue. */
|
||||
ptr += req->length * sizeof(request_t);
|
||||
memcpy(ptr, rsp->ring, rsp->length *
|
||||
sizeof(response_t));
|
||||
ptr += req->length * req_entry_size;
|
||||
memcpy(ptr, rsp->ring, rsp->length * rsp_entry_size);
|
||||
|
||||
return ptr + (rsp->length * sizeof(response_t));
|
||||
return ptr + (rsp->length * rsp_entry_size);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -606,6 +607,8 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, __be32 **last_chain)
|
||||
struct req_que *req;
|
||||
struct rsp_que *rsp;
|
||||
int que;
|
||||
size_t req_entry_size = qla_req_entry_size(ha);
|
||||
size_t rsp_entry_size = qla_rsp_entry_size(ha);
|
||||
|
||||
if (!ha->mqenable)
|
||||
return ptr;
|
||||
@@ -623,19 +626,19 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, __be32 **last_chain)
|
||||
q->chain_size = htonl(
|
||||
sizeof(struct qla2xxx_mqueue_chain) +
|
||||
sizeof(struct qla2xxx_mqueue_header) +
|
||||
(req->length * sizeof(request_t)));
|
||||
(req->length * req_entry_size));
|
||||
ptr += sizeof(struct qla2xxx_mqueue_chain);
|
||||
|
||||
/* Add header. */
|
||||
qh = ptr;
|
||||
qh->queue = htonl(TYPE_REQUEST_QUEUE);
|
||||
qh->number = htonl(que);
|
||||
qh->size = htonl(req->length * sizeof(request_t));
|
||||
qh->size = htonl(req->length * req_entry_size);
|
||||
ptr += sizeof(struct qla2xxx_mqueue_header);
|
||||
|
||||
/* Add data. */
|
||||
memcpy(ptr, req->ring, req->length * sizeof(request_t));
|
||||
ptr += req->length * sizeof(request_t);
|
||||
memcpy(ptr, req->ring, req->length * req_entry_size);
|
||||
ptr += req->length * req_entry_size;
|
||||
}
|
||||
|
||||
/* Response queues */
|
||||
@@ -651,19 +654,19 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, __be32 **last_chain)
|
||||
q->chain_size = htonl(
|
||||
sizeof(struct qla2xxx_mqueue_chain) +
|
||||
sizeof(struct qla2xxx_mqueue_header) +
|
||||
(rsp->length * sizeof(response_t)));
|
||||
(rsp->length * rsp_entry_size));
|
||||
ptr += sizeof(struct qla2xxx_mqueue_chain);
|
||||
|
||||
/* Add header. */
|
||||
qh = ptr;
|
||||
qh->queue = htonl(TYPE_RESPONSE_QUEUE);
|
||||
qh->number = htonl(que);
|
||||
qh->size = htonl(rsp->length * sizeof(response_t));
|
||||
qh->size = htonl(rsp->length * rsp_entry_size);
|
||||
ptr += sizeof(struct qla2xxx_mqueue_header);
|
||||
|
||||
/* Add data. */
|
||||
memcpy(ptr, rsp->ring, rsp->length * sizeof(response_t));
|
||||
ptr += rsp->length * sizeof(response_t);
|
||||
memcpy(ptr, rsp->ring, rsp->length * rsp_entry_size);
|
||||
ptr += rsp->length * rsp_entry_size;
|
||||
}
|
||||
|
||||
return ptr;
|
||||
|
||||
@@ -337,6 +337,7 @@ static inline void wrt_reg_dword(volatile __le32 __iomem *addr, u32 data)
|
||||
|
||||
#define MAX_CMDSZ 16 /* SCSI maximum CDB size. */
|
||||
#include "qla_fw.h"
|
||||
#include "qla_fw29.h"
|
||||
|
||||
struct name_list_extended {
|
||||
struct get_name_list_extended *l;
|
||||
@@ -576,7 +577,7 @@ struct srb_iocb {
|
||||
__le16 comp_status;
|
||||
|
||||
uint8_t modifier;
|
||||
uint8_t vp_index;
|
||||
uint16_t vp_index;
|
||||
uint16_t loop_id;
|
||||
} tmf;
|
||||
struct {
|
||||
@@ -1278,6 +1279,7 @@ static inline bool qla2xxx_is_valid_mbs(unsigned int mbs)
|
||||
#define MBC_LOAD_RISC_RAM 9 /* Load RAM command. */
|
||||
#define MBC_DUMP_RISC_RAM 0xa /* Dump RAM command. */
|
||||
#define MBC_SECURE_FLASH_UPDATE 0xa /* Secure Flash Update(28xx) */
|
||||
#define MBC_RD_WR_FLASH 0xa /* Read/write Dword/block Flash(29xx) */
|
||||
#define MBC_LOAD_RISC_RAM_EXTENDED 0xb /* Load RAM extended. */
|
||||
#define MBC_DUMP_RISC_RAM_EXTENDED 0xc /* Dump RAM extended. */
|
||||
#define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */
|
||||
@@ -1547,6 +1549,11 @@ typedef struct {
|
||||
#define PD_STATE_PORT_LOGOUT 10
|
||||
#define PD_STATE_WAIT_PORT_LOGOUT_ACK 11
|
||||
|
||||
enum qla29xx_mpi_optrom_op {
|
||||
QLA29XX_MPI_OP_DUMP,
|
||||
QLA29XX_MPI_OP_LOAD,
|
||||
};
|
||||
|
||||
|
||||
#define QLA_ZIO_MODE_6 (BIT_2 | BIT_1)
|
||||
#define QLA_ZIO_DISABLED 0
|
||||
@@ -1988,6 +1995,18 @@ typedef struct {
|
||||
#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */
|
||||
} response_t;
|
||||
|
||||
struct response_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
uint32_t handle; /* System defined handle */
|
||||
uint8_t data[52];
|
||||
uint32_t signature;
|
||||
uint8_t reserved[64];
|
||||
#define RESPONSE_PROCESSED 0xDEADDEAD /* Signature */
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - ATIO queue entry definition.
|
||||
*/
|
||||
@@ -2066,6 +2085,24 @@ typedef struct {
|
||||
struct dsd64 dsd[2];
|
||||
} cmd_a64_entry_t, request_t;
|
||||
|
||||
struct request_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
uint32_t handle; /* System handle. */
|
||||
target_id_t target; /* SCSI ID */
|
||||
__le16 lun; /* SCSI LUN */
|
||||
__le16 control_flags; /* Control flags. */
|
||||
uint16_t reserved_1;
|
||||
__le16 timeout; /* Command timeout. */
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */
|
||||
uint32_t byte_count; /* Total byte count. */
|
||||
struct dsd64 dsd[2];
|
||||
uint8_t reserved[64];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - continuation entry structure definition.
|
||||
*/
|
||||
@@ -2324,6 +2361,15 @@ typedef struct {
|
||||
uint8_t reserved_2[48];
|
||||
} mrk_entry_t;
|
||||
|
||||
/* 29xx definitions */
|
||||
struct sts_cont_entry_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
uint8_t data[124]; /* data */
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - Management Server entry structure definition.
|
||||
*/
|
||||
@@ -2482,6 +2528,14 @@ struct imm_ntfy_from_isp {
|
||||
#define REQUEST_ENTRY_SIZE (sizeof(request_t))
|
||||
|
||||
|
||||
/*
|
||||
* 29xx (qla29xx) uses 128-byte ring entries for both request and response
|
||||
* queues. These macros give the size of an extended IOCB slot and are
|
||||
* used when allocating from / zeroing the 29xx request ring via ring_ext_ptr.
|
||||
*/
|
||||
#define RESPONSE_ENTRY_SIZE_EXT (sizeof(struct response_ext))
|
||||
#define REQUEST_ENTRY_SIZE_EXT (sizeof(struct request_ext))
|
||||
|
||||
|
||||
/*
|
||||
* Switch info gathering structure.
|
||||
@@ -3503,6 +3557,13 @@ struct isp_operations {
|
||||
int (*write_optrom)(struct scsi_qla_host *, void *, uint32_t,
|
||||
uint32_t);
|
||||
|
||||
void *(*read_optrom_region)(struct scsi_qla_host *vha,
|
||||
uint16_t reg_code, uint16_t opts, void *buf,
|
||||
uint32_t offset, uint32_t length);
|
||||
int (*write_optrom_region)(struct scsi_qla_host *vha,
|
||||
uint16_t reg_code, uint16_t opts, void *buf,
|
||||
uint32_t offset, uint32_t length);
|
||||
|
||||
int (*get_flash_version) (struct scsi_qla_host *, void *);
|
||||
int (*start_scsi) (srb_t *);
|
||||
int (*start_scsi_mq) (srb_t *);
|
||||
@@ -3528,7 +3589,6 @@ struct isp_operations {
|
||||
#define QLA_MIDX_DEFAULT 0
|
||||
#define QLA_MIDX_RSP_Q 1
|
||||
#define QLA_PCI_MSIX_CONTROL 0xa2
|
||||
#define QLA_83XX_PCI_MSIX_CONTROL 0x92
|
||||
|
||||
struct scsi_qla_host;
|
||||
|
||||
@@ -3737,6 +3797,14 @@ struct rsp_que {
|
||||
dma_addr_t dma;
|
||||
response_t *ring;
|
||||
response_t *ring_ptr;
|
||||
/*
|
||||
* 29xx extended IOCB ring (128-byte entries) aliases of ring/ring_ptr.
|
||||
* Allocated when IS_QLA29XX(ha); set up at queue-init time to point at
|
||||
* the same DMA memory as 'ring' but typed for the 29xx stride. 24xx
|
||||
* code paths walk via ring_ptr; 29xx paths walk via ring_ext_ptr.
|
||||
*/
|
||||
struct response_ext *ring_ext;
|
||||
struct response_ext *ring_ext_ptr;
|
||||
__le32 __iomem *rsp_q_in; /* FWI2-capable only. */
|
||||
__le32 __iomem *rsp_q_out;
|
||||
uint16_t ring_index;
|
||||
@@ -3764,6 +3832,14 @@ struct req_que {
|
||||
dma_addr_t dma;
|
||||
request_t *ring;
|
||||
request_t *ring_ptr;
|
||||
/*
|
||||
* 29xx extended IOCB ring (128-byte entries) aliases of ring/ring_ptr.
|
||||
* Allocated when IS_QLA29XX(ha); set up at queue-init time to point at
|
||||
* the same DMA memory as 'ring' but typed for the 29xx stride. 24xx
|
||||
* code paths must not run on 29xx HW, and vice-versa.
|
||||
*/
|
||||
struct request_ext *ring_ext;
|
||||
struct request_ext *ring_ext_ptr;
|
||||
__le32 __iomem *req_q_in; /* FWI2-capable only. */
|
||||
__le32 __iomem *req_q_out;
|
||||
uint16_t ring_index;
|
||||
@@ -4171,6 +4247,7 @@ struct qla_hw_data {
|
||||
#define EEH_FLUSH_RDY 1
|
||||
#define EEH_FLUSH_DONE 2
|
||||
uint32_t secure_mcu:1;
|
||||
uint32_t valid_flt:1;
|
||||
} flags;
|
||||
|
||||
uint16_t max_exchg;
|
||||
@@ -4256,6 +4333,7 @@ struct qla_hw_data {
|
||||
#define PORT_SPEED_16GB 0x05
|
||||
#define PORT_SPEED_32GB 0x06
|
||||
#define PORT_SPEED_64GB 0x07
|
||||
#define PORT_SPEED_128GB 0x08
|
||||
#define PORT_SPEED_10GB 0x13
|
||||
uint16_t link_data_rate; /* F/W operating speed */
|
||||
uint16_t set_data_rate; /* Set by user */
|
||||
@@ -4287,6 +4365,10 @@ struct qla_hw_data {
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP2089 0x2089
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP2281 0x2281
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP2289 0x2289
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP2099 0x2099
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP2299 0x2299
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP2091 0x2091
|
||||
#define PCI_DEVICE_ID_QLOGIC_ISP2291 0x2291
|
||||
|
||||
uint32_t isp_type;
|
||||
#define DT_ISP2100 BIT_0
|
||||
@@ -4316,7 +4398,11 @@ struct qla_hw_data {
|
||||
#define DT_ISP2089 BIT_24
|
||||
#define DT_ISP2281 BIT_25
|
||||
#define DT_ISP2289 BIT_26
|
||||
#define DT_ISP_LAST (DT_ISP2289 << 1)
|
||||
#define DT_ISP2299 BIT_27
|
||||
#define DT_ISP2099 BIT_28
|
||||
#define DT_ISP2091 BIT_29
|
||||
#define DT_ISP2291 BIT_30
|
||||
#define DT_ISP_LAST ((uint32_t)DT_ISP2291 << 1)
|
||||
|
||||
uint32_t device_type;
|
||||
#define DT_T10_PI BIT_25
|
||||
@@ -4353,6 +4439,10 @@ struct qla_hw_data {
|
||||
#define IS_QLA2261(ha) (DT_MASK(ha) & DT_ISP2261)
|
||||
#define IS_QLA2081(ha) (DT_MASK(ha) & DT_ISP2081)
|
||||
#define IS_QLA2281(ha) (DT_MASK(ha) & DT_ISP2281)
|
||||
#define IS_QLA2299(ha) (DT_MASK(ha) & DT_ISP2299)
|
||||
#define IS_QLA2099(ha) (DT_MASK(ha) & DT_ISP2099)
|
||||
#define IS_QLA2091(ha) (DT_MASK(ha) & DT_ISP2091)
|
||||
#define IS_QLA2291(ha) (DT_MASK(ha) & DT_ISP2291)
|
||||
|
||||
#define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
|
||||
IS_QLA6312(ha) || IS_QLA6322(ha))
|
||||
@@ -4363,6 +4453,9 @@ struct qla_hw_data {
|
||||
#define IS_QLA84XX(ha) (IS_QLA8432(ha))
|
||||
#define IS_QLA27XX(ha) (IS_QLA2071(ha) || IS_QLA2271(ha) || IS_QLA2261(ha))
|
||||
#define IS_QLA28XX(ha) (IS_QLA2081(ha) || IS_QLA2281(ha))
|
||||
#define IS_QLA29XX(ha) (IS_QLA2099(ha) || IS_QLA2299(ha) || \
|
||||
IS_QLA2091(ha) || IS_QLA2291(ha))
|
||||
|
||||
#define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \
|
||||
IS_QLA84XX(ha))
|
||||
#define IS_CNA_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha) || \
|
||||
@@ -4372,9 +4465,10 @@ struct qla_hw_data {
|
||||
IS_QLA25XX(ha) || IS_QLA81XX(ha) || \
|
||||
IS_QLA82XX(ha) || IS_QLA83XX(ha) || \
|
||||
IS_QLA8044(ha) || IS_QLA27XX(ha) || \
|
||||
IS_QLA28XX(ha))
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
#define IS_MSIX_NACK_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha) || \
|
||||
IS_QLA29XX(ha))
|
||||
#define IS_NOPOLLING_TYPE(ha) (IS_QLA81XX(ha) && (ha)->flags.msix_enabled)
|
||||
#define IS_FAC_REQUIRED(ha) (IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
@@ -4390,9 +4484,9 @@ struct qla_hw_data {
|
||||
#define HAS_EXTENDED_IDS(ha) ((ha)->device_type & DT_EXTENDED_IDS)
|
||||
#define IS_CT6_SUPPORTED(ha) ((ha)->device_type & DT_CT6_SUPPORTED)
|
||||
#define IS_MQUE_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
|
||||
IS_QLA28XX(ha))
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
#define IS_BIDI_CAPABLE(ha) \
|
||||
(IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
(IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
/* Bit 21 of fw_attributes decides the MCTP capabilities */
|
||||
#define IS_MCTP_CAPABLE(ha) (IS_QLA2031(ha) && \
|
||||
((ha)->fw_attributes_ext[0] & BIT_0))
|
||||
@@ -4408,18 +4502,19 @@ struct qla_hw_data {
|
||||
(QLA_NVME_IOS(_sp) && QLA_ABTS_FW_ENABLED(_sp->fcport->vha->hw))
|
||||
|
||||
#define IS_PI_UNINIT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
|
||||
IS_QLA28XX(ha))
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
#define IS_PI_IPGUARD_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
|
||||
IS_QLA28XX(ha))
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
#define IS_PI_DIFB_DIX0_CAPABLE(ha) (0)
|
||||
#define IS_PI_SPLIT_DET_CAPABLE_HBA(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
|
||||
IS_QLA28XX(ha))
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
#define IS_PI_SPLIT_DET_CAPABLE(ha) (IS_PI_SPLIT_DET_CAPABLE_HBA(ha) && \
|
||||
(((ha)->fw_attributes_h << 16 | (ha)->fw_attributes) & BIT_22))
|
||||
#define IS_ATIO_MSIX_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
|
||||
IS_QLA28XX(ha))
|
||||
#define IS_TGT_MODE_CAPABLE(ha) (ha->tgt.atio_q_length)
|
||||
#define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
#define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha) || IS_QLA28XX(ha) || \
|
||||
IS_QLA29XX(ha))
|
||||
#define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
|
||||
IS_QLA28XX(ha))
|
||||
#define IS_FAWWN_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha) || \
|
||||
@@ -4452,6 +4547,7 @@ struct qla_hw_data {
|
||||
uint16_t vpd_size;
|
||||
uint16_t vpd_base;
|
||||
void *vpd;
|
||||
struct qla_flash_memo_block *fiv;
|
||||
|
||||
uint16_t loop_reset_delay;
|
||||
uint8_t retry_count;
|
||||
@@ -4483,6 +4579,8 @@ struct qla_hw_data {
|
||||
|
||||
struct qla_flt_header *flt;
|
||||
dma_addr_t flt_dma;
|
||||
struct qla_flash_layout *flt_data;
|
||||
uint32_t fw_dump_tmplt_len;
|
||||
|
||||
#define XGMAC_DATA_SIZE 4096
|
||||
void *xgmac_data;
|
||||
@@ -4707,6 +4805,9 @@ struct qla_hw_data {
|
||||
uint32_t fdt_protect_sec_cmd;
|
||||
uint32_t fdt_wrt_sts_reg_cmd;
|
||||
|
||||
#define QLA_SEGMENT_LENGTH 0x25000
|
||||
uint32_t flt_segment_length;
|
||||
|
||||
struct {
|
||||
uint32_t flt_region_flt;
|
||||
uint32_t flt_region_fdt;
|
||||
@@ -4900,6 +5001,7 @@ struct active_regions {
|
||||
#define QLA_SET_DATA_RATE_LR 2 /* Set speed and initiate LR */
|
||||
|
||||
#define QLA_DEFAULT_PAYLOAD_SIZE 64
|
||||
#define QLA_MAX_IOCB_SIZE 128
|
||||
/*
|
||||
* This item might be allocated with a size > sizeof(struct purex_item).
|
||||
* The "size" variable gives the size of the payload (which
|
||||
@@ -4914,7 +5016,7 @@ struct purex_item {
|
||||
atomic_t in_use;
|
||||
uint16_t size;
|
||||
struct {
|
||||
uint8_t iocb[64];
|
||||
u8 iocb[QLA_MAX_IOCB_SIZE];
|
||||
} iocb;
|
||||
};
|
||||
|
||||
@@ -5333,6 +5435,14 @@ static inline bool qla_vha_mark_busy(scsi_qla_host_t *vha)
|
||||
/*
|
||||
* Flash support definitions
|
||||
*/
|
||||
#define check_and_set_mbc_bits(bopt, dopt, bit_to_check, bit_to_set) { \
|
||||
if (bopt & bit_to_check) \
|
||||
dopt |= bit_to_set; \
|
||||
}
|
||||
|
||||
#define SET_FW_BIT(__opts, bit) ((__opts) |= (bit))
|
||||
#define CLEAR_FW_BIT(__opts, bit) ((__opts) &= ~(bit))
|
||||
|
||||
#define OPTROM_SIZE_2300 0x20000
|
||||
#define OPTROM_SIZE_2322 0x100000
|
||||
#define OPTROM_SIZE_24XX 0x100000
|
||||
@@ -5474,9 +5584,9 @@ struct sff_8247_a0 {
|
||||
/* BPM -- Buffer Plus Management support. */
|
||||
#define IS_BPM_CAPABLE(ha) \
|
||||
(IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) || \
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
#define IS_BPM_RANGE_CAPABLE(ha) \
|
||||
(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
#define IS_BPM_ENABLED(vha) \
|
||||
(ql2xautodetectsfp && !vha->vp_idx && IS_BPM_CAPABLE(vha->hw))
|
||||
|
||||
@@ -5597,4 +5707,9 @@ struct ql_vnd_tgt_stats_resp {
|
||||
(!_fcport || IS_SESSION_DELETED(_fcport) || atomic_read(&_fcport->state) != FCS_ONLINE || \
|
||||
!_fcport->vha->hw->flags.fw_started)
|
||||
|
||||
#define is_flash_read(_opt) \
|
||||
(!(_opt & BIT_9) && !(_opt & BIT_6))
|
||||
|
||||
#define is_flash_write(_opt) \
|
||||
(!(_opt & BIT_9) && (_opt & BIT_6))
|
||||
#endif
|
||||
|
||||
@@ -497,7 +497,7 @@ qla2x00_dfs_fce_write(struct file *file, const char __user *buffer,
|
||||
unsigned long enable;
|
||||
|
||||
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) {
|
||||
ql_dbg(ql_dbg_user, vha, 0xd034,
|
||||
"this adapter does not support FCE.");
|
||||
return -EINVAL;
|
||||
@@ -698,7 +698,7 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
goto out;
|
||||
|
||||
if (qla2x00_dfs_root)
|
||||
|
||||
@@ -2534,7 +2534,7 @@ qla24xx_sa_replace_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb)
|
||||
|
||||
void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
|
||||
{
|
||||
struct purex_entry_24xx *p = *pkt;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct enode *ptr;
|
||||
int sid;
|
||||
u16 totlen;
|
||||
@@ -2544,26 +2544,55 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
|
||||
struct fc_port *fcport;
|
||||
struct qla_els_pt_arg a;
|
||||
be_id_t beid;
|
||||
__le16 nport_handle;
|
||||
__le32 rx_xchg_addr;
|
||||
__le16 ox_id;
|
||||
__le16 frame_size, status_flags, trunc_frame_size;
|
||||
uint8_t s_id[3], d_id[3];
|
||||
uint8_t vp_idx;
|
||||
struct purex_entry_24xx *p = *pkt;
|
||||
|
||||
memset(&a, 0, sizeof(a));
|
||||
|
||||
/*
|
||||
* purex_entry_24xx_ext (29xx) overlays purex_entry_24xx for every
|
||||
* field touched here -- nport_handle, rx_xchg_addr, ox_id, frame_size,
|
||||
* status_flags, trunc_frame_size, s_id[3], d_id[3] -- with only
|
||||
* vp_idx differing in width (u8 at offset 6 vs __le16 at offsets 6-7,
|
||||
* with reserved2 at offset 7 in the 24xx layout). So all reads but
|
||||
* vp_idx go through a single struct purex_entry_24xx * view.
|
||||
*/
|
||||
nport_handle = p->nport_handle;
|
||||
rx_xchg_addr = p->rx_xchg_addr;
|
||||
ox_id = p->ox_id;
|
||||
frame_size = p->frame_size;
|
||||
status_flags = p->status_flags;
|
||||
trunc_frame_size = p->trunc_frame_size;
|
||||
memcpy(s_id, p->s_id, sizeof(s_id));
|
||||
memcpy(d_id, p->d_id, sizeof(d_id));
|
||||
if (IS_QLA29XX(ha))
|
||||
vp_idx = le16_to_cpu(((struct purex_entry_24xx_ext *)
|
||||
*pkt)->vp_idx);
|
||||
else
|
||||
vp_idx = p->vp_idx;
|
||||
|
||||
a.els_opcode = ELS_AUTH_ELS;
|
||||
a.nport_handle = p->nport_handle;
|
||||
a.rx_xchg_address = p->rx_xchg_addr;
|
||||
a.did.b.domain = p->s_id[2];
|
||||
a.did.b.area = p->s_id[1];
|
||||
a.did.b.al_pa = p->s_id[0];
|
||||
a.nport_handle = nport_handle;
|
||||
a.rx_xchg_address = rx_xchg_addr;
|
||||
a.did.b.domain = s_id[2];
|
||||
a.did.b.area = s_id[1];
|
||||
a.did.b.al_pa = s_id[0];
|
||||
a.tx_byte_count = a.tx_len = sizeof(struct fc_els_ls_rjt);
|
||||
a.tx_addr = vha->hw->elsrej.cdma;
|
||||
a.tx_addr = ha->elsrej.cdma;
|
||||
a.vp_idx = vha->vp_idx;
|
||||
a.control_flags = EPD_ELS_RJT;
|
||||
a.ox_id = le16_to_cpu(p->ox_id);
|
||||
a.ox_id = le16_to_cpu(ox_id);
|
||||
|
||||
sid = p->s_id[0] | (p->s_id[1] << 8) | (p->s_id[2] << 16);
|
||||
sid = s_id[0] | (s_id[1] << 8) | (s_id[2] << 16);
|
||||
|
||||
totlen = (le16_to_cpu(p->frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
|
||||
if (le16_to_cpu(p->status_flags) & 0x8000) {
|
||||
totlen = le16_to_cpu(p->trunc_frame_size);
|
||||
totlen = (le16_to_cpu(frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
|
||||
if (le16_to_cpu(status_flags) & 0x8000) {
|
||||
totlen = le16_to_cpu(trunc_frame_size);
|
||||
qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
|
||||
__qla_consume_iocb(vha, pkt, rsp);
|
||||
return;
|
||||
@@ -2600,12 +2629,12 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
|
||||
purex = &ptr->u.purexinfo;
|
||||
purex->pur_info.pur_sid = a.did;
|
||||
purex->pur_info.pur_bytes_rcvd = totlen;
|
||||
purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr);
|
||||
purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle);
|
||||
purex->pur_info.pur_did.b.domain = p->d_id[2];
|
||||
purex->pur_info.pur_did.b.area = p->d_id[1];
|
||||
purex->pur_info.pur_did.b.al_pa = p->d_id[0];
|
||||
purex->pur_info.vp_idx = p->vp_idx;
|
||||
purex->pur_info.pur_rx_xchg_address = le32_to_cpu(rx_xchg_addr);
|
||||
purex->pur_info.pur_nphdl = le16_to_cpu(nport_handle);
|
||||
purex->pur_info.pur_did.b.domain = d_id[2];
|
||||
purex->pur_info.pur_did.b.area = d_id[1];
|
||||
purex->pur_info.pur_did.b.al_pa = d_id[0];
|
||||
purex->pur_info.vp_idx = vp_idx;
|
||||
|
||||
a.sid = purex->pur_info.pur_did;
|
||||
|
||||
@@ -2989,6 +3018,21 @@ qla28xx_start_scsi_edif(srb_t *sp)
|
||||
struct req_que *req = sp->qpair->req;
|
||||
spinlock_t *lock = sp->qpair->qp_lock_ptr;
|
||||
|
||||
/*
|
||||
* EDIF on 29xx is not supported by this driver yet. The EDIF fast
|
||||
* path builds 64-byte cmd_type_6 IOCBs and advances req->ring_ptr
|
||||
* with a 64-byte stride, which would corrupt the 128-byte extended
|
||||
* request ring that 29xx hardware uses. A proper 29xx EDIF port
|
||||
* requires a cmd_type_6_ext-shaped submission path; until that is
|
||||
* implemented, refuse the command rather than risk ring corruption.
|
||||
*/
|
||||
if (IS_QLA29XX(ha)) {
|
||||
ql_log(ql_log_warn, vha, 0x13ae,
|
||||
"EDIF is not supported on 29xx hardware; failing cmd sp=%p.\n",
|
||||
sp);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
/* Setup device pointers. */
|
||||
cmd = GET_CMD_SP(sp);
|
||||
|
||||
@@ -3129,7 +3173,8 @@ qla28xx_start_scsi_edif(srb_t *sp)
|
||||
* Five DSDs are available in the Continuation
|
||||
* Type 1 IOCB.
|
||||
*/
|
||||
cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req);
|
||||
cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
|
||||
ha, req);
|
||||
cur_dsd = cont_pkt->dsd;
|
||||
avail_dsds = 5;
|
||||
}
|
||||
@@ -3485,12 +3530,18 @@ static void __chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
|
||||
}
|
||||
|
||||
void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
|
||||
srb_t *sp, struct sts_entry_24xx *sts24)
|
||||
srb_t *sp, void *pkt)
|
||||
{
|
||||
struct sts_entry_24xx *sts24 = pkt;
|
||||
struct sts_entry_24xx_ext *stsext = pkt;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
fc_port_t *fcport = sp->fcport;
|
||||
/* sa_index used by this iocb */
|
||||
struct scsi_cmnd *cmd = GET_CMD_SP(sp);
|
||||
uint32_t handle;
|
||||
uint16_t sa_index;
|
||||
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
handle = (uint32_t)LSW(sts24->handle);
|
||||
|
||||
@@ -3498,8 +3549,12 @@ void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
|
||||
if (cmd->sc_data_direction != DMA_FROM_DEVICE)
|
||||
return;
|
||||
|
||||
return __chk_edif_rx_sa_delete_pending(vha, fcport, handle,
|
||||
le16_to_cpu(sts24->edif_sa_index));
|
||||
if (IS_QLA29XX(ha))
|
||||
sa_index = le16_to_cpu(stsext->read_sa_index);
|
||||
else
|
||||
sa_index = le16_to_cpu(sts24->edif_sa_index);
|
||||
|
||||
return __chk_edif_rx_sa_delete_pending(vha, fcport, handle, sa_index);
|
||||
}
|
||||
|
||||
void qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
|
||||
|
||||
@@ -1538,7 +1538,7 @@ struct vp_rpt_id_entry_24xx {
|
||||
#define TOPO_N2N 0x4
|
||||
#define TOPO_F 0x6
|
||||
|
||||
uint16_t fip_flags;
|
||||
__le16 fip_flags;
|
||||
uint8_t rsv2[12];
|
||||
|
||||
uint8_t ls_rjt_vendor;
|
||||
@@ -1548,13 +1548,13 @@ struct vp_rpt_id_entry_24xx {
|
||||
|
||||
uint8_t port_name[8];
|
||||
uint8_t node_name[8];
|
||||
uint16_t bbcr;
|
||||
__le16 bbcr;
|
||||
uint8_t reserved_5[6];
|
||||
} f1;
|
||||
struct _f2 { /* format 2: N2N direct connect */
|
||||
uint8_t vpstat1_subcode;
|
||||
uint8_t flags;
|
||||
uint16_t fip_flags;
|
||||
__le16 fip_flags;
|
||||
uint8_t rsv2[12];
|
||||
|
||||
uint8_t ls_rjt_vendor;
|
||||
@@ -1564,7 +1564,7 @@ struct vp_rpt_id_entry_24xx {
|
||||
|
||||
uint8_t port_name[8];
|
||||
uint8_t node_name[8];
|
||||
uint16_t bbcr;
|
||||
__le16 bbcr;
|
||||
uint8_t reserved_5[2];
|
||||
uint8_t remote_nport_id[4];
|
||||
} f2;
|
||||
@@ -1676,6 +1676,8 @@ struct qla_flt_location {
|
||||
#define FLT_REG_VPD_SEC_27XX_2 0xD8
|
||||
#define FLT_REG_VPD_SEC_27XX_3 0xDA
|
||||
#define FLT_REG_NVME_PARAMS_27XX 0x21
|
||||
#define FLT_REG_FMB_PRI 0xDF
|
||||
#define FLT_REG_FMB_SEC 0x124
|
||||
|
||||
/* 28xx */
|
||||
#define FLT_REG_AUX_IMG_PRI_28XX 0x125
|
||||
@@ -1695,6 +1697,10 @@ struct qla_flt_location {
|
||||
#define FLT_REG_NVME_PARAMS_PRI_28XX 0x14E
|
||||
#define FLT_REG_NVME_PARAMS_SEC_28XX 0x179
|
||||
|
||||
/* 29xx */
|
||||
#define FLT_REG_MINI_FLT 0x201
|
||||
#define FLT_REG_FW_DUMP_TMPLT 0x1A0
|
||||
|
||||
struct qla_flt_region {
|
||||
__le16 code;
|
||||
uint8_t attribute;
|
||||
@@ -1716,6 +1722,56 @@ struct qla_flt_header {
|
||||
#define FLT_MAX_REGIONS 0xFF
|
||||
#define FLT_REGIONS_SIZE (FLT_REGION_SIZE * FLT_MAX_REGIONS)
|
||||
|
||||
/* 29xx */
|
||||
#define FLT_HDR_VERSION 0x2
|
||||
|
||||
struct qla_flt_region_header {
|
||||
__le32 signature;
|
||||
__le32 version;
|
||||
__le32 length;
|
||||
__le32 checksum;
|
||||
__le16 region_count;
|
||||
__le16 region_size;
|
||||
__le32 segment_size;
|
||||
__le32 res3;
|
||||
__le32 res4;
|
||||
__le32 res5;
|
||||
__le32 res6;
|
||||
__le32 res7;
|
||||
__le32 res8;
|
||||
__le32 res9;
|
||||
__le32 res10;
|
||||
__le32 res11;
|
||||
__le32 res12;
|
||||
};
|
||||
|
||||
struct qla_flt_region_data {
|
||||
__le16 region_code;
|
||||
__le16 reserved;
|
||||
__le32 attribute;
|
||||
__le32 image_length;
|
||||
__le32 mbi_offset;
|
||||
__le32 version;
|
||||
__le32 card_type;
|
||||
__le32 chip_revision;
|
||||
__le32 res4;
|
||||
__le32 res5;
|
||||
__le32 res6;
|
||||
__le32 res7;
|
||||
__le32 res8;
|
||||
__le32 res9;
|
||||
__le32 res10;
|
||||
__le32 res11;
|
||||
__le32 res12;
|
||||
};
|
||||
|
||||
struct qla_flash_layout {
|
||||
struct qla_flt_region_header flt_header;
|
||||
struct qla_flt_region_data region[];
|
||||
};
|
||||
|
||||
#define FLT_DATA_MAX_REGIONS 0xFF
|
||||
|
||||
/* Flash NPIV Configuration Table ********************************************/
|
||||
|
||||
struct qla_npiv_header {
|
||||
@@ -2056,7 +2112,7 @@ struct nvram_81xx {
|
||||
* BIT 7 = SCM Disabled if BIT is set (1)
|
||||
* BIT 8-15 = Unused
|
||||
*/
|
||||
uint16_t enhanced_features;
|
||||
__le16 enhanced_features;
|
||||
|
||||
uint16_t reserved_24[4];
|
||||
|
||||
@@ -2284,4 +2340,78 @@ struct qla_fcp_prio_cfg {
|
||||
|
||||
#define NVRAM_DUAL_FCP_NVME_FLAG_OFFSET 0x196
|
||||
|
||||
struct qla_fmb_version {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
uint8_t sub;
|
||||
uint8_t build;
|
||||
};
|
||||
|
||||
struct qla_fmb_upd_time {
|
||||
__le16 year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
|
||||
uint8_t hour;
|
||||
uint8_t minute;
|
||||
uint8_t second;
|
||||
uint8_t reserved;
|
||||
};
|
||||
|
||||
struct qla_flash_memo_block {
|
||||
__le32 signature; /* "FMBS" */
|
||||
#define QLFC_FMB_SIG cpu_to_le32(0x53424D46)
|
||||
__le32 length;
|
||||
__le32 version;
|
||||
#define QLFC_FMB_VERSION 3
|
||||
__le32 checksum;
|
||||
struct qla_fmb_version ffv_ver;
|
||||
struct qla_fmb_version mbi_ver;
|
||||
struct {
|
||||
__le16 year;
|
||||
uint8_t month;
|
||||
uint8_t day;
|
||||
uint8_t reserve[4];
|
||||
} bld_time;
|
||||
uint8_t tool_id[4];
|
||||
struct qla_fmb_upd_time upd_time;
|
||||
struct qla_fmb_version tool_version;
|
||||
};
|
||||
|
||||
#define TIM_DEST_ADDR 0xffffffff
|
||||
#define CHUNK_SIZE 0x10000
|
||||
|
||||
#define TIM 0
|
||||
#define ARR1 1
|
||||
#define ARR2 2
|
||||
#define ARR3 3
|
||||
#define ARR4 4
|
||||
|
||||
#define LD_FL_HEADER_SIGNATURE 0x46434F50
|
||||
#define LD_FL_HEADER_VERSION 0x01
|
||||
#define LD_FL_HEADER_SIZE (0x14 * 4)
|
||||
|
||||
struct fcop_header {
|
||||
uint32_t signature;
|
||||
uint32_t header_length;
|
||||
uint32_t header_version;
|
||||
uint32_t segment_size;
|
||||
uint32_t tim_length;
|
||||
uint32_t fc_major_version;
|
||||
uint32_t fc_minor_version;
|
||||
uint32_t fc_subminor_version;
|
||||
uint32_t array1_length;
|
||||
uint32_t array1_destination_addr;
|
||||
uint32_t array2_length;
|
||||
uint32_t array2_destination_addr;
|
||||
uint32_t array3_length;
|
||||
uint32_t array4_length;
|
||||
uint32_t attribute;
|
||||
uint32_t extended_attribute;
|
||||
uint32_t reserved0;
|
||||
uint32_t reserved1;
|
||||
uint32_t reserved2;
|
||||
uint32_t image_checksum;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
830
drivers/scsi/qla2xxx/qla_fw29.h
Normal file
830
drivers/scsi/qla2xxx/qla_fw29.h
Normal file
@@ -0,0 +1,830 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* QLogic Fibre Channel HBA Driver
|
||||
* Copyright (c) 2026- Marvell.
|
||||
*
|
||||
* See LICENSE.qla2xxx for copyright and licensing details.
|
||||
*/
|
||||
#ifndef __QLA_FW29_H
|
||||
#define __QLA_FW29_H
|
||||
|
||||
#include "qla_fw.h"
|
||||
|
||||
/* Control Flags 2 common for cmd6 and 7 */
|
||||
#define CF2_VMID_ENABLE BIT_0
|
||||
#define CF2_CSCTL_PRIORITY_TAG BIT_1
|
||||
#define CF2_NO_TRNF_READY_ENABLE BIT_2
|
||||
#define CF2_RX_ID_ENABLE BIT_3
|
||||
|
||||
/*
|
||||
* vp_index layout for 29xx extended command IOCBs
|
||||
* (cmd_type_6_ext, cmd_type_7_ext, cmd_type_crc_2_ext, ...):
|
||||
* bits [8:0] - VP index (9 bits)
|
||||
* bits [15:9] - reserved, must be zero
|
||||
* Access on a host-endian value via le16_to_cpu(vp_index) & CMD_EXT_VP_INDEX_MASK.
|
||||
*/
|
||||
#define CMD_EXT_VP_INDEX_MASK 0x01ff
|
||||
|
||||
/*
|
||||
* Combined vp_index/sof_type field layout (used by ELS and ABTS ext IOCBs):
|
||||
* bits [8:0] - VP index (9 bits)
|
||||
* bits [11:9] - reserved
|
||||
* bits [15:12] - SOF type (4 bits)
|
||||
*/
|
||||
#define EXT_VP_SOF_VP_INDEX_MASK 0x01ff
|
||||
#define EXT_VP_SOF_SOF_TYPE_SHIFT 12
|
||||
#define EXT_VP_SOF_SOF_TYPE_MASK 0xf000
|
||||
|
||||
static inline u16 qla_ext_get_vp_index(__le16 vp_sof)
|
||||
{
|
||||
return le16_to_cpu(vp_sof) & EXT_VP_SOF_VP_INDEX_MASK;
|
||||
}
|
||||
|
||||
static inline u16 qla_ext_get_sof_type(__le16 vp_sof)
|
||||
{
|
||||
return (le16_to_cpu(vp_sof) >> EXT_VP_SOF_SOF_TYPE_SHIFT) & 0xf;
|
||||
}
|
||||
|
||||
static inline __le16 qla_ext_build_vp_sof(u16 vp_idx, u16 sof_type)
|
||||
{
|
||||
return cpu_to_le16((vp_idx & EXT_VP_SOF_VP_INDEX_MASK) |
|
||||
((sof_type & 0xf) << EXT_VP_SOF_SOF_TYPE_SHIFT));
|
||||
}
|
||||
|
||||
/*
|
||||
* Combined vp_idx/vp_status field layout (vp_rpt_id_entry_24xx_ext):
|
||||
* bits [8:0] - VP index (9 bits)
|
||||
* bits [15:9] - VP status (7 bits)
|
||||
*/
|
||||
#define EXT_VP_STATUS_VP_INDEX_MASK 0x01ff
|
||||
#define EXT_VP_STATUS_VP_STATUS_SHIFT 9
|
||||
#define EXT_VP_STATUS_VP_STATUS_MASK 0xfe00
|
||||
|
||||
/*
|
||||
* ISP queue - command entry structure definition.
|
||||
*/
|
||||
#define NUM_CMD67_DSDS 4
|
||||
struct cmd_type_6_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
|
||||
__le16 fcp_rsp_dsd_len; /* FCP_RSP DSD length. */
|
||||
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
|
||||
__le16 control_flags; /* Control flags. */
|
||||
|
||||
__le16 fcp_cmnd_dseg_len; /* Data segment length. */
|
||||
/* Data segment address. */
|
||||
__le64 fcp_cmnd_dseg_address __packed;
|
||||
/* Data segment address. */
|
||||
__le64 fcp_rsp_dseg_address __packed;
|
||||
|
||||
__le32 byte_count; /* Total byte count. */
|
||||
__le16 control_flags_2; /* Control flags 2. */
|
||||
|
||||
__le16 vp_index; /* VP Index 9bits*/
|
||||
__le32 fburstlen_rxid; /* First Burst length/RX ID */
|
||||
__le16 io_tag; /* I/O Tag */
|
||||
uint8_t vl_n_fctl; /* VL (7-4) | RSVD (3-2) | F_CTL [17] (1) | RSVD (0) */
|
||||
uint8_t prtag_csctl; /* Priority Tag or CS_CTL */
|
||||
__le32 src_vm_id; /* Source VM ID */
|
||||
uint8_t reserved_2[16]; /* Reserved */
|
||||
struct dsd64 dsd[NUM_CMD67_DSDS]; /* Data Segment Descriptors */
|
||||
};
|
||||
|
||||
struct cmd_type_7_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
uint32_t handle; /* System handle. */
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
uint16_t reserved_1;
|
||||
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
|
||||
__le16 task_mgmt_flags; /* Task management flags. */
|
||||
|
||||
uint8_t task;
|
||||
uint8_t crn;
|
||||
uint8_t fcp_cdb[MAX_CMDSZ]; /* SCSI command words. */
|
||||
__le32 byte_count; /* Total byte count. */
|
||||
__le16 ctrl_flags_2; /* Control flags 2 */
|
||||
__le16 vp_index; /* VP Index 9bits*/
|
||||
__le32 rx_id; /* Receive Exchange ID */
|
||||
__le16 io_tag; /* I/O Tag */
|
||||
uint8_t vl_n_fctl; /* VL (7-4) | RSVD (3-2) | F_CTL [17] (1) | RSVD (0) */
|
||||
uint8_t reserved_3[21]; /* Reserved */
|
||||
struct dsd64 dsd[NUM_CMD67_DSDS]; /* Data Segment Descriptors */
|
||||
};
|
||||
|
||||
/*
|
||||
* Inline data-DSD capacity of the 29xx cmd_type_crc_2_ext IOCB. Unlike
|
||||
* cmd_type_6_ext / cmd_type_7_ext (which carry NUM_CMD67_DSDS inline DSDs),
|
||||
* CRC_2 places the bulk of its DSDs in the separate CRC-context DMA; only
|
||||
* a single data_dsd is carried inline in both the u.nobundling and
|
||||
* u.bundling variants. Use this constant wherever the IOCB-reservation
|
||||
* calculator needs the CRC_2 ext inline capacity so it stays in sync with
|
||||
* the firmware-facing layout below.
|
||||
*/
|
||||
#define NUM_CRC2_EXT_INLINE_DSDS 1
|
||||
|
||||
struct cmd_type_crc_2_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
__le16 fcp_rsp_dseg_len; /* FCP_RSP DSD length. */
|
||||
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
|
||||
__le16 control_flags_1; /* Control flags. */
|
||||
__le16 fcp_cmnd_dseg_len; /* Data segment length. */
|
||||
|
||||
__le64 fcp_cmnd_dseg_address __packed;
|
||||
/* Data segment address. */
|
||||
__le64 fcp_rsp_dseg_address __packed;
|
||||
|
||||
__le32 byte_count; /* Total byte count. */
|
||||
|
||||
__le16 control_flags_2; /* Control flags - 2 */
|
||||
__le16 vp_index; /* VP Index (bits [8:0]); bits [15:9] reserved.
|
||||
* See CMD_EXT_VP_INDEX_MASK.
|
||||
*/
|
||||
|
||||
uint32_t reserved_1;
|
||||
|
||||
__le16 iocb_tag; /* Unused */
|
||||
__le16 vl_prio; /* Bit 1 - F_CTL, Bits 4-7 VL, rest are rsvd */
|
||||
|
||||
uint32_t reserved_2; /* 3C-3F offset */
|
||||
|
||||
__le32 ref_tag;
|
||||
uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/
|
||||
|
||||
__le16 app_tag;
|
||||
uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/
|
||||
|
||||
__le16 blk_size; /* Data size in bytes */
|
||||
__le16 prot_opts; /* Requested Data Protection Mode */
|
||||
|
||||
__le32 tot_byte_count; /* Total byte count/ total data
|
||||
* transfer count
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
uint32_t reserved_1; /* offset 54 */
|
||||
uint16_t reserved_2;
|
||||
__le16 guard_seed; /* offset 5A */
|
||||
struct dsd64 data_dsd[1];
|
||||
uint32_t reserved_5[2];
|
||||
uint32_t reserved_6;
|
||||
} nobundling;
|
||||
struct {
|
||||
__le32 dif_byte_count; /* Total DIF byte
|
||||
* count
|
||||
*/
|
||||
__le16 dseg_count; /* Data segment count */
|
||||
__le16 guard_seed; /* Initial Guard Seed */
|
||||
struct dsd64 data_dsd[1];
|
||||
struct dsd64 dif_dsd;
|
||||
} bundling;
|
||||
} u;
|
||||
uint8_t reserved_3[12]; /* MUST be set to 0. */
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - status entry structure definition.
|
||||
*/
|
||||
struct sts_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
__le16 ox_id; /* OX_ID used by the firmware. */
|
||||
|
||||
__le32 residual_len; /* FW calc residual transfer length. */
|
||||
|
||||
union {
|
||||
__le16 reserved_1;
|
||||
__le16 nvme_rsp_pyld_len;
|
||||
} u1;
|
||||
|
||||
__le16 state_flags; /* State flags. */
|
||||
|
||||
__le16 read_sa_index;
|
||||
__le16 wr_sa_index;
|
||||
uint8_t reserved_2[8];
|
||||
uint8_t act_dif[8];
|
||||
uint8_t exp_dif[8];
|
||||
union {
|
||||
struct {
|
||||
__le32 rsp_data_len_dma; /* FCP response data length */
|
||||
uint8_t reserved_3[76];
|
||||
};
|
||||
struct {
|
||||
uint8_t nvme_ersp_data[32];
|
||||
uint8_t reserved_4[48];
|
||||
};
|
||||
struct {
|
||||
__le32 bid_rd_rsp_residual_count; /* BID read rsp residual cnt */
|
||||
__le16 retry_delay_timer; /* Retry delay timer. */
|
||||
__le16 scsi_status; /* SCSI status. */
|
||||
__le32 rsp_residual_count; /* FCP RSP residual count. */
|
||||
__le32 sense_len; /* FCP SENSE length. */
|
||||
__le32 rsp_data_len_ndma; /* FCP response data length */
|
||||
uint8_t data[60]; /* FCP rsp/sense information */
|
||||
};
|
||||
} u2;
|
||||
|
||||
/*
|
||||
* If DIF Error is set in comp_status, these additional fields are
|
||||
* defined:
|
||||
*
|
||||
* !!! NOTE: Firmware sends expected/actual DIF data in big endian
|
||||
* format; but all of the "data" field gets swab32-d in the beginning
|
||||
* of qla2900_status_entry().
|
||||
*
|
||||
* &data[10] : uint8_t report_runt_bg[2]; - computed guard
|
||||
* &data[12] : uint8_t actual_dif[8]; - DIF Data received
|
||||
* &data[20] : uint8_t expected_dif[8]; - DIF Data computed
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - marker entry structure definition.
|
||||
*/
|
||||
struct mrk_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t handle_count; /* Handle count. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
uint8_t modifier; /* Modifier (7-0). */
|
||||
uint8_t reserved_1;
|
||||
|
||||
__le16 vp_index; /* VP Index. 9bits*/
|
||||
uint16_t reserved_3;
|
||||
|
||||
uint8_t lun[8]; /* FCP LUN (BE). */
|
||||
uint8_t reserved_4[104];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - CT Pass-Through entry structure definition.
|
||||
*/
|
||||
#define NUM_CT_DSDS 5
|
||||
struct ct_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System Defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
__le16 cmd_dsd_count;
|
||||
|
||||
__le16 vp_index; /* vp index 9 bits*/
|
||||
|
||||
__le16 timeout; /* Command timeout. */
|
||||
uint16_t reserved_2;
|
||||
|
||||
__le16 rsp_dsd_count;
|
||||
|
||||
uint8_t reserved_3[10];
|
||||
uint8_t reserved_4[28]; /* Reserved. */
|
||||
|
||||
__le32 rsp_byte_count;
|
||||
__le32 cmd_byte_count;
|
||||
struct dsd64 dsd[NUM_CT_DSDS]; /* Data Segment Descriptors */
|
||||
};
|
||||
|
||||
/*
|
||||
* 29xx extended Link Service pass-through request IOCB (128 bytes).
|
||||
*
|
||||
* Same wire purpose as the 64-byte struct pt_ls4_request used on 24xx-class
|
||||
* adapters, but laid out for the 128-byte 29xx request ring:
|
||||
* - vp_index widened to __le16 (bits [8:0] meaningful, see
|
||||
* CMD_EXT_VP_INDEX_MASK).
|
||||
* - reserved area expanded to 32 bytes between exchange_address and
|
||||
* rx_byte_count.
|
||||
* - inline DSD capacity grown from 2 to 5.
|
||||
* Header through 'tx_dseg_count' (offset 14) and the control_flags /
|
||||
* exchange_address fields keep the same offsets as struct pt_ls4_request,
|
||||
* so common code can populate them via either type once IS_QLA29XX(ha) is
|
||||
* branched for the layout-divergent fields.
|
||||
*/
|
||||
#define NUM_PT_LS4_EXT_DSDS 5
|
||||
struct pt_ls4_request_ext {
|
||||
uint8_t entry_type;
|
||||
uint8_t entry_count;
|
||||
uint8_t sys_define;
|
||||
uint8_t entry_status;
|
||||
uint32_t handle;
|
||||
__le16 status;
|
||||
__le16 nport_handle;
|
||||
__le16 tx_dseg_count;
|
||||
__le16 vp_index; /* VP Index 9 bits; see CMD_EXT_VP_INDEX_MASK */
|
||||
__le16 timeout;
|
||||
__le16 control_flags; /* CF_LS4_* (see struct pt_ls4_request) */
|
||||
__le16 rx_dseg_count;
|
||||
__le16 rsvd2;
|
||||
__le32 exchange_address;
|
||||
uint8_t rsvd3[32];
|
||||
__le32 rx_byte_count;
|
||||
__le32 tx_byte_count;
|
||||
struct dsd64 dsd[NUM_PT_LS4_EXT_DSDS];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - PUREX IOCB entry structure definition
|
||||
*/
|
||||
struct purex_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
__le16 reserved1;
|
||||
__le16 vp_idx; /* VP index 9 bits*/
|
||||
|
||||
__le16 status_flags;
|
||||
__le16 nport_handle;
|
||||
|
||||
__le16 frame_size;
|
||||
__le16 trunc_frame_size;
|
||||
|
||||
__le32 rx_xchg_addr;
|
||||
|
||||
uint8_t d_id[3];
|
||||
uint8_t r_ctl;
|
||||
|
||||
uint8_t s_id[3];
|
||||
uint8_t cs_ctl;
|
||||
|
||||
uint8_t f_ctl[3];
|
||||
uint8_t type;
|
||||
|
||||
__le16 seq_cnt;
|
||||
uint8_t df_ctl;
|
||||
uint8_t seq_id;
|
||||
|
||||
__le16 rx_id;
|
||||
__le16 ox_id;
|
||||
__le32 param;
|
||||
|
||||
uint8_t els_frame_payload[84];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - ELS Pass-Through entry structure definition.
|
||||
* ELS_EXT_EST_SOFI*: 4-bit sof_type for extended IOCBs (qla_fw.h EST_SOFI*
|
||||
* is for els_entry_24xx byte layout).
|
||||
*/
|
||||
#define ELS_EXT_EST_SOFI3 (1 << 1)
|
||||
#define ELS_EXT_EST_SOFI2 (3 << 3)
|
||||
|
||||
struct els_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System Defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 comp_status; /* response only */
|
||||
__le16 nport_handle;
|
||||
|
||||
__le16 tx_dsd_count;
|
||||
|
||||
__le16 vp_index_sof; /* bits [8:0]=VP index, [15:12]=SOF type */
|
||||
|
||||
__le32 rx_xchg_address; /* Receive exchange address. */
|
||||
__le16 rx_dsd_count;
|
||||
|
||||
uint8_t opcode;
|
||||
uint8_t reserved_2;
|
||||
|
||||
uint8_t d_id[3];
|
||||
uint8_t s_id[3];
|
||||
|
||||
__le16 control_flags; /* Control flags. */
|
||||
|
||||
union {
|
||||
struct {
|
||||
__le32 rx_byte_count;
|
||||
__le32 tx_byte_count;
|
||||
|
||||
__le64 tx_address __packed; /* DSD 0 address. */
|
||||
__le32 tx_len; /* DSD 0 length. */
|
||||
|
||||
__le64 rx_address __packed; /* DSD 1 address. */
|
||||
__le32 rx_len; /* DSD 1 length. */
|
||||
};
|
||||
struct {
|
||||
__le32 total_byte_count;
|
||||
__le32 error_subcode_1;
|
||||
__le32 error_subcode_2;
|
||||
__le32 error_subcode_3;
|
||||
uint8_t reserved_3[16];
|
||||
};
|
||||
};
|
||||
uint8_t reserved_4[64];
|
||||
};
|
||||
|
||||
struct els_sts_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System Defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
__le32 handle; /* System handle. */
|
||||
|
||||
__le16 comp_status;
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
__le16 reserved_1;
|
||||
|
||||
__le16 vp_index_sof; /* bits [8:0]=VP index, [15:12]=SOF type */
|
||||
|
||||
__le32 rx_xchg_address; /* Receive exchange address. */
|
||||
__le16 reserved_2;
|
||||
|
||||
uint8_t opcode;
|
||||
uint8_t reserved_3;
|
||||
|
||||
uint8_t d_id[3];
|
||||
uint8_t s_id[3];
|
||||
|
||||
__le16 control_flags; /* Control flags. */
|
||||
__le32 total_byte_count;
|
||||
__le32 error_subcode_1;
|
||||
__le32 error_subcode_2;
|
||||
__le32 error_subcode_3;
|
||||
|
||||
uint8_t reserved_4[80];
|
||||
};
|
||||
|
||||
struct logio_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
__le16 control_flags; /* Control flags. */
|
||||
|
||||
__le16 vp_index; /* VP Index 9bits*/
|
||||
|
||||
uint8_t port_id[3]; /* PortID of destination port. */
|
||||
|
||||
uint8_t rsp_size; /* Response size in 32bit words. */
|
||||
|
||||
__le32 io_parameter[11]; /* General I/O parameters. */
|
||||
uint8_t reserved_2[64]; /* Reserved*/
|
||||
};
|
||||
|
||||
struct tsk_mgmt_entry_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t handle_count; /* Handle count. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
__le16 reserved_1;
|
||||
|
||||
__le16 delay; /* Activity delay in seconds. */
|
||||
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
|
||||
__le32 control_flags; /* Control Flags. */
|
||||
|
||||
__le16 vp_index; /* VP Index 9bits */
|
||||
|
||||
uint8_t reserved_3[98];
|
||||
};
|
||||
|
||||
struct abort_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t handle_count; /* Handle count. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
union {
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 comp_status; /* Completion status. */
|
||||
};
|
||||
|
||||
__le16 options; /* Options. */
|
||||
|
||||
uint32_t handle_to_abort; /* System handle to abort. */
|
||||
|
||||
__le16 req_que_no;
|
||||
|
||||
__le16 vp_index; /* VP Index 9bits*/
|
||||
u8 reserved_2[4];
|
||||
union {
|
||||
struct {
|
||||
__le16 abts_rty_cnt;
|
||||
__le16 rsp_timeout;
|
||||
} drv;
|
||||
struct {
|
||||
u8 ba_rjt_vendorUnique;
|
||||
u8 ba_rjt_reasonCodeExpl;
|
||||
u8 ba_rjt_reasonCode;
|
||||
u8 reserved_3;
|
||||
} fw;
|
||||
};
|
||||
u8 reserved_4[100];
|
||||
};
|
||||
|
||||
struct abts_entry_24xx_ext {
|
||||
uint8_t entry_type;
|
||||
uint8_t entry_count;
|
||||
uint8_t handle_count;
|
||||
uint8_t entry_status;
|
||||
|
||||
__le32 handle; /* type 0x55 only */
|
||||
|
||||
__le16 comp_status; /* type 0x55 only */
|
||||
__le16 nport_handle; /* type 0x54 only */
|
||||
|
||||
__le16 control_flags; /* type 0x55 only */
|
||||
__le16 vp_idx_sof; /* bits [8:0]=VP index, [15:12]=SOF type */
|
||||
|
||||
__le32 rx_xch_addr;
|
||||
|
||||
uint8_t d_id[3];
|
||||
uint8_t r_ctl;
|
||||
|
||||
uint8_t s_id[3];
|
||||
uint8_t cs_ctl;
|
||||
|
||||
uint8_t f_ctl[3];
|
||||
uint8_t type;
|
||||
|
||||
__le16 seq_cnt;
|
||||
uint8_t df_ctl;
|
||||
uint8_t seq_id;
|
||||
|
||||
__le16 rx_id;
|
||||
__le16 ox_id;
|
||||
|
||||
__le32 param;
|
||||
|
||||
union {
|
||||
struct {
|
||||
__le32 subcode3;
|
||||
__le32 rsvd;
|
||||
__le32 subcode1;
|
||||
__le32 subcode2;
|
||||
} error;
|
||||
struct {
|
||||
__le16 rsrvd1;
|
||||
uint8_t last_seq_id;
|
||||
uint8_t seq_id_valid;
|
||||
__le16 aborted_rx_id;
|
||||
__le16 aborted_ox_id;
|
||||
__le16 high_seq_cnt;
|
||||
__le16 low_seq_cnt;
|
||||
} ba_acc;
|
||||
struct {
|
||||
uint8_t vendor_unique;
|
||||
uint8_t explanation;
|
||||
uint8_t reason;
|
||||
} ba_rjt;
|
||||
} payload;
|
||||
|
||||
__le32 rx_xch_addr_to_abort;
|
||||
uint8_t reserved_2[64];
|
||||
} __packed;
|
||||
/*
|
||||
* Virtual Port Control IOCB
|
||||
*/
|
||||
struct vp_ctrl_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 vp_idx_failed;
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
|
||||
__le16 command;
|
||||
|
||||
__le16 vp_count;
|
||||
|
||||
uint8_t vp_idx_map[16];
|
||||
__le16 flags;
|
||||
__le16 id;
|
||||
uint16_t reserved_4;
|
||||
__le16 hopct;
|
||||
uint8_t reserved_5[88];
|
||||
};
|
||||
|
||||
/*
|
||||
* Modify Virtual Port Configuration IOCB
|
||||
*/
|
||||
struct vp_config_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t handle_count;
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 flags;
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
|
||||
uint8_t command;
|
||||
|
||||
uint8_t vp_count;
|
||||
|
||||
uint8_t vp_index1;
|
||||
uint8_t vp_index2;
|
||||
|
||||
uint8_t options_idx1;
|
||||
uint8_t hard_address_idx1;
|
||||
uint16_t reserved_vp1;
|
||||
uint8_t port_name_idx1[WWN_SIZE];
|
||||
uint8_t node_name_idx1[WWN_SIZE];
|
||||
|
||||
uint8_t options_idx2;
|
||||
uint8_t hard_address_idx2;
|
||||
uint16_t reserved_vp2;
|
||||
uint8_t port_name_idx2[WWN_SIZE];
|
||||
uint8_t node_name_idx2[WWN_SIZE];
|
||||
__le16 id;
|
||||
uint16_t reserved_4;
|
||||
__le16 hopct;
|
||||
uint8_t reserved_5[66];
|
||||
};
|
||||
|
||||
struct vp_rpt_id_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
__le32 resv1;
|
||||
uint8_t vp_acquired;
|
||||
uint8_t vp_setup;
|
||||
__le16 vp_idx_status; /* bits [8:0]=VP index, [15:9]=VP status */
|
||||
|
||||
uint8_t port_id[3];
|
||||
uint8_t format;
|
||||
union {
|
||||
struct vp_rpt_id_ext_f1 {
|
||||
/* format 1 fabric */
|
||||
uint8_t vpstat1_subcode; /* vp_status=1 subcode */
|
||||
uint8_t flags;
|
||||
|
||||
__le16 fip_flags;
|
||||
uint8_t rsv2[12];
|
||||
|
||||
uint8_t ls_rjt_vendor;
|
||||
uint8_t ls_rjt_explanation;
|
||||
uint8_t ls_rjt_reason;
|
||||
uint8_t rsv3;
|
||||
__le16 rsv8;
|
||||
__le16 flogi_acc_payload_size; /* bits [8:0] meaningful */
|
||||
uint8_t port_name[8];
|
||||
uint8_t node_name[8];
|
||||
__le16 bbcr;
|
||||
uint8_t reserved_5[6];
|
||||
} f1;
|
||||
struct vp_rpt_id_ext_f2 { /* format 2: N2N direct connect */
|
||||
uint8_t vpstat1_subcode;
|
||||
uint8_t flags;
|
||||
__le16 fip_flags;
|
||||
uint8_t rsv2[12];
|
||||
|
||||
uint8_t ls_rjt_vendor;
|
||||
uint8_t ls_rjt_explanation;
|
||||
uint8_t ls_rjt_reason;
|
||||
uint8_t rsv3[5];
|
||||
|
||||
uint8_t port_name[8];
|
||||
uint8_t node_name[8];
|
||||
__le16 bbcr;
|
||||
uint8_t reserved_5[2];
|
||||
uint8_t remote_nport_id[4];
|
||||
} f2;
|
||||
} u;
|
||||
uint8_t reserved_end[64];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - 64-Bit addressing, continuation entry structure definition
|
||||
* for the 29xx extended (128-byte) IOCB ring. Mirrors cont_a64_entry_t
|
||||
* but carries 10 DSDs per entry instead of 5.
|
||||
*/
|
||||
#define NUM_CONT1_DSDS 10
|
||||
struct cont_a64_entry_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
uint32_t reserved;
|
||||
struct dsd64 dsd[NUM_CONT1_DSDS];
|
||||
};
|
||||
|
||||
/*
|
||||
* 29xx extended Command Type FC-NVMe IOCB (128 bytes).
|
||||
*
|
||||
* The header layout up through 'byte_count' (offset 48) is identical to the
|
||||
* 64-byte struct cmd_nvme used by 24xx-class adapters, so common code can
|
||||
* populate those fields via either type. Fields beyond 'byte_count' diverge:
|
||||
* 29xx adds control_flags_2/vp_index/first_burst_rx_id/io_tag/..., drops
|
||||
* port_id[3]+vp_index(byte), and carries NUM_NVME_DSDS inline DSDs.
|
||||
*/
|
||||
#define NUM_NVME_DSDS 4
|
||||
struct cmd_nvme_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
__le16 nvme_rsp_dsd_len; /* NVMe RSP DSD length */
|
||||
|
||||
uint64_t rsvd;
|
||||
|
||||
__le16 control_flags; /* Control Flags (see struct cmd_nvme) */
|
||||
__le16 nvme_cmnd_dseg_len; /* Data segment length. */
|
||||
|
||||
__le64 nvme_cmnd_dseg_address __packed; /* Data segment address. */
|
||||
|
||||
__le64 nvme_rsp_dseg_address __packed; /* Data segment address. */
|
||||
|
||||
__le32 byte_count; /* Total byte count. */
|
||||
|
||||
__le16 control_flags_2;
|
||||
/*
|
||||
* vp_index layout matches the other 29xx extended IOCBs: only bits
|
||||
* [8:0] are meaningful (see CMD_EXT_VP_INDEX_MASK).
|
||||
*/
|
||||
__le16 vp_index;
|
||||
__le32 first_burst_rx_id;
|
||||
__le16 io_tag;
|
||||
uint8_t vl_n_fctl; /* VL(7:4) | RSVD(3:2) | F_CTL[17](1) | RSVD(0) */
|
||||
uint8_t prtag_csctl; /* Priority Tag or CS_CTL */
|
||||
__le32 src_vm_id; /* Source VM ID */
|
||||
uint8_t reserved_2[16];
|
||||
|
||||
struct dsd64 nvme_dsd[NUM_NVME_DSDS];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -38,6 +38,7 @@ extern void qla24xx_update_fw_options(scsi_qla_host_t *);
|
||||
extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
|
||||
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
|
||||
extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *);
|
||||
extern int qla29xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr);
|
||||
|
||||
extern int qla2x00_perform_loop_resync(scsi_qla_host_t *);
|
||||
extern int qla2x00_loop_resync(scsi_qla_host_t *);
|
||||
@@ -135,7 +136,7 @@ void qla_edif_sadb_release(struct qla_hw_data *ha);
|
||||
int qla_edif_sadb_build_free_pool(struct qla_hw_data *ha);
|
||||
void qla_edif_sadb_release_free_pool(struct qla_hw_data *ha);
|
||||
void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
|
||||
srb_t *sp, struct sts_entry_24xx *sts24);
|
||||
srb_t *sp, void *pkt);
|
||||
void qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
|
||||
struct ctio7_from_24xx *ctio);
|
||||
void qla2x00_release_all_sadb(struct scsi_qla_host *vha, struct fc_port *fcport);
|
||||
@@ -265,8 +266,7 @@ extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
|
||||
extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
|
||||
extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
|
||||
extern int qla24xx_configure_vhba (scsi_qla_host_t *);
|
||||
extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
|
||||
struct vp_rpt_id_entry_24xx *);
|
||||
extern void qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt);
|
||||
extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
|
||||
extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
|
||||
extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *);
|
||||
@@ -294,9 +294,11 @@ void qla_adjust_buf(struct scsi_qla_host *);
|
||||
* Global Function Prototypes in qla_iocb.c source file.
|
||||
*/
|
||||
void qla_els_pt_iocb(struct scsi_qla_host *vha,
|
||||
struct els_entry_24xx *pkt, struct qla_els_pt_arg *a);
|
||||
void *pkt, struct qla_els_pt_arg *a);
|
||||
cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha,
|
||||
struct req_que *que);
|
||||
struct qla_hw_data *ha, struct req_que *que);
|
||||
struct cont_a64_entry_ext *qla2900_prep_cont_type1_iocb(scsi_qla_host_t *vha,
|
||||
struct req_que *req);
|
||||
extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
|
||||
extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
|
||||
extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
|
||||
@@ -336,7 +338,7 @@ void qla2x00_els_dcmd2_iocb_timeout(void *data);
|
||||
* Global Function Prototypes in qla_mbx.c source file.
|
||||
*/
|
||||
extern int
|
||||
qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
|
||||
qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t, int);
|
||||
|
||||
extern int
|
||||
qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
|
||||
@@ -580,6 +582,12 @@ extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t,
|
||||
extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t,
|
||||
uint32_t);
|
||||
void qla_no_op_mb(struct scsi_qla_host *vha);
|
||||
extern int qla29xx_flash_block_read(scsi_qla_host_t *vha, dma_addr_t req_dma,
|
||||
uint32_t flash_addr, uint32_t flash_size,
|
||||
uint16_t reg_code, uint16_t opt);
|
||||
extern int qla29xx_flash_block_write(scsi_qla_host_t *vha, dma_addr_t req_dma,
|
||||
uint32_t flash_addr, uint32_t flash_size,
|
||||
uint16_t reg_code, uint16_t opt);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_isr.c source file.
|
||||
@@ -682,7 +690,19 @@ struct purex_item *qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha,
|
||||
void **pkt, struct rsp_que **rsp, bool is_purls, bool byte_order);
|
||||
int qla_mailbox_passthru(scsi_qla_host_t *vha, uint16_t *mbx_in,
|
||||
uint16_t *mbx_out);
|
||||
|
||||
void *qla29xx_read_optrom_data(struct scsi_qla_host *vha,
|
||||
uint16_t reg_code, uint16_t opts,
|
||||
void *buf, uint32_t offset,
|
||||
uint32_t length);
|
||||
extern int qla29xx_write_optrom_data(struct scsi_qla_host *vha,
|
||||
uint16_t reg_code, uint16_t opts,
|
||||
void *buf, uint32_t offset,
|
||||
uint32_t length);
|
||||
extern int qla29xx_mpi_optrom_data(struct scsi_qla_host *vha, uint16_t opts,
|
||||
void *buf, uint32_t offset, uint32_t length,
|
||||
enum qla29xx_mpi_optrom_op op);
|
||||
extern int qla29xx_load_dump_mpi(scsi_qla_host_t *vha, uint16_t opt,
|
||||
uint32_t mpi_addr, uint32_t dlen, dma_addr_t req_dma);
|
||||
/*
|
||||
* Global Function Prototypes in qla_dbg.c source file.
|
||||
*/
|
||||
@@ -968,10 +988,8 @@ extern void qla24xx_process_purex_list(struct purex_list *);
|
||||
extern void qla2x00_dfs_create_rport(scsi_qla_host_t *vha, struct fc_port *fp);
|
||||
extern void qla2x00_dfs_remove_rport(scsi_qla_host_t *vha, struct fc_port *fp);
|
||||
extern void qla_wait_nvme_release_cmd_kref(srb_t *sp);
|
||||
extern void qla_nvme_abort_set_option
|
||||
(struct abort_entry_24xx *abt, srb_t *sp);
|
||||
extern void qla_nvme_abort_process_comp_status
|
||||
(struct abort_entry_24xx *abt, srb_t *sp);
|
||||
extern void qla_nvme_abort_set_option(void *pkt, srb_t *sp);
|
||||
extern void qla_nvme_abort_process_comp_status(void *pkt, srb_t *sp);
|
||||
struct scsi_qla_host *qla_find_host_by_vp_idx(struct scsi_qla_host *vha,
|
||||
uint16_t vp_idx);
|
||||
|
||||
|
||||
@@ -68,30 +68,62 @@ void *
|
||||
qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct ct_entry_24xx *ct_pkt;
|
||||
|
||||
ct_pkt = (struct ct_entry_24xx *)arg->iocb;
|
||||
memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct ct_entry_24xx_ext *ct_pkt;
|
||||
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle = cpu_to_le16(arg->nport_handle);
|
||||
ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size);
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size);
|
||||
ct_pkt = (struct ct_entry_24xx_ext *)arg->iocb;
|
||||
memset(ct_pkt, 0, sizeof(struct ct_entry_24xx_ext));
|
||||
|
||||
put_unaligned_le64(arg->req_dma, &ct_pkt->dsd[0].address);
|
||||
ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle = cpu_to_le16(arg->nport_handle);
|
||||
ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size);
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size);
|
||||
|
||||
put_unaligned_le64(arg->rsp_dma, &ct_pkt->dsd[1].address);
|
||||
ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
|
||||
ct_pkt->vp_index = vha->vp_idx;
|
||||
put_unaligned_le64(arg->req_dma,
|
||||
&ct_pkt->dsd[0].address);
|
||||
ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
|
||||
|
||||
vha->qla_stats.control_requests++;
|
||||
put_unaligned_le64(arg->rsp_dma,
|
||||
&ct_pkt->dsd[1].address);
|
||||
ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
|
||||
ct_pkt->vp_index = cpu_to_le16(vha->vp_idx);
|
||||
|
||||
return (ct_pkt);
|
||||
vha->qla_stats.control_requests++;
|
||||
|
||||
return ct_pkt;
|
||||
} else {
|
||||
struct ct_entry_24xx *ct_pkt;
|
||||
|
||||
ct_pkt = (struct ct_entry_24xx *)arg->iocb;
|
||||
memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
|
||||
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle = cpu_to_le16(arg->nport_handle);
|
||||
ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size);
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size);
|
||||
|
||||
put_unaligned_le64(arg->req_dma,
|
||||
&ct_pkt->dsd[0].address);
|
||||
ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
|
||||
|
||||
put_unaligned_le64(arg->rsp_dma,
|
||||
&ct_pkt->dsd[1].address);
|
||||
ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
|
||||
ct_pkt->vp_index = vha->vp_idx;
|
||||
|
||||
vha->qla_stats.control_requests++;
|
||||
|
||||
return ct_pkt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,7 +164,10 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
|
||||
routine, ms_pkt->entry_status, vha->d_id.b.domain,
|
||||
vha->d_id.b.area, vha->d_id.b.al_pa);
|
||||
} else {
|
||||
if (IS_FWI2_CAPABLE(ha))
|
||||
if (IS_QLA29XX(ha))
|
||||
comp_status = le16_to_cpu(
|
||||
((struct ct_entry_24xx_ext *)ms_pkt)->comp_status);
|
||||
else if (IS_FWI2_CAPABLE(ha))
|
||||
comp_status = le16_to_cpu(
|
||||
((struct ct_entry_24xx *)ms_pkt)->comp_status);
|
||||
else
|
||||
@@ -157,8 +192,8 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
|
||||
break;
|
||||
case CS_PORT_LOGGED_OUT:
|
||||
if (IS_FWI2_CAPABLE(ha)) {
|
||||
if (le16_to_cpu(ms_pkt->loop_id.extended) ==
|
||||
NPH_SNS)
|
||||
if (le16_to_cpu(((struct ct_entry_24xx *)
|
||||
ms_pkt)->nport_handle) == NPH_SNS)
|
||||
lid_is_sns = true;
|
||||
} else {
|
||||
if (le16_to_cpu(ms_pkt->loop_id.extended) ==
|
||||
@@ -1437,42 +1472,85 @@ void *
|
||||
qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size,
|
||||
uint32_t rsp_size)
|
||||
{
|
||||
struct ct_entry_24xx *ct_pkt;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
|
||||
memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct ct_entry_24xx_ext *ct_pkt;
|
||||
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id);
|
||||
ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
|
||||
ct_pkt = (struct ct_entry_24xx_ext *)ha->ms_iocb;
|
||||
memset(ct_pkt, 0, sizeof(struct ct_entry_24xx_ext));
|
||||
|
||||
put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[0].address);
|
||||
ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle =
|
||||
cpu_to_le16(vha->mgmt_svr_loop_id);
|
||||
ct_pkt->timeout =
|
||||
cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
|
||||
|
||||
put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[1].address);
|
||||
ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
|
||||
ct_pkt->vp_index = vha->vp_idx;
|
||||
put_unaligned_le64(ha->ct_sns_dma,
|
||||
&ct_pkt->dsd[0].address);
|
||||
ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
|
||||
|
||||
return ct_pkt;
|
||||
put_unaligned_le64(ha->ct_sns_dma,
|
||||
&ct_pkt->dsd[1].address);
|
||||
ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
|
||||
ct_pkt->vp_index = cpu_to_le16(vha->vp_idx);
|
||||
|
||||
return ct_pkt;
|
||||
} else {
|
||||
struct ct_entry_24xx *ct_pkt;
|
||||
|
||||
ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
|
||||
memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
|
||||
|
||||
ct_pkt->entry_type = CT_IOCB_TYPE;
|
||||
ct_pkt->entry_count = 1;
|
||||
ct_pkt->nport_handle =
|
||||
cpu_to_le16(vha->mgmt_svr_loop_id);
|
||||
ct_pkt->timeout =
|
||||
cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
ct_pkt->cmd_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_dsd_count = cpu_to_le16(1);
|
||||
ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
|
||||
|
||||
put_unaligned_le64(ha->ct_sns_dma,
|
||||
&ct_pkt->dsd[0].address);
|
||||
ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
|
||||
|
||||
put_unaligned_le64(ha->ct_sns_dma,
|
||||
&ct_pkt->dsd[1].address);
|
||||
ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count;
|
||||
ct_pkt->vp_index = vha->vp_idx;
|
||||
|
||||
return ct_pkt;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
|
||||
struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
|
||||
|
||||
if (IS_FWI2_CAPABLE(ha)) {
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct ct_entry_24xx_ext *ct_pkt =
|
||||
(struct ct_entry_24xx_ext *)ha->ms_iocb;
|
||||
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
|
||||
ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
|
||||
} else if (IS_FWI2_CAPABLE(ha)) {
|
||||
struct ct_entry_24xx *ct_pkt =
|
||||
(struct ct_entry_24xx *)ha->ms_iocb;
|
||||
|
||||
ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
|
||||
ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count;
|
||||
} else {
|
||||
ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
|
||||
|
||||
ms_pkt->req_bytecount = cpu_to_le32(req_size);
|
||||
ms_pkt->req_dsd.length = ms_pkt->req_bytecount;
|
||||
}
|
||||
@@ -1508,12 +1586,18 @@ qla25xx_fdmi_port_speed_capability(struct qla_hw_data *ha)
|
||||
|
||||
if (IS_CNA_CAPABLE(ha))
|
||||
return FDMI_PORT_SPEED_10GB;
|
||||
if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
|
||||
if (ha->max_supported_speed == 2) {
|
||||
if (IS_QLA28XX(ha) || IS_QLA27XX(ha) || IS_QLA29XX(ha)) {
|
||||
if (ha->max_supported_speed == 3) {
|
||||
if (ha->min_supported_speed <= 7)
|
||||
speeds |= FDMI_PORT_SPEED_128GB;
|
||||
}
|
||||
if (ha->max_supported_speed == 3 ||
|
||||
ha->max_supported_speed == 2) {
|
||||
if (ha->min_supported_speed <= 6)
|
||||
speeds |= FDMI_PORT_SPEED_64GB;
|
||||
}
|
||||
if (ha->max_supported_speed == 2 ||
|
||||
if (ha->max_supported_speed == 3 ||
|
||||
ha->max_supported_speed == 2 ||
|
||||
ha->max_supported_speed == 1) {
|
||||
if (ha->min_supported_speed <= 5)
|
||||
speeds |= FDMI_PORT_SPEED_32GB;
|
||||
@@ -1577,6 +1661,8 @@ qla25xx_fdmi_port_speed_currently(struct qla_hw_data *ha)
|
||||
return FDMI_PORT_SPEED_32GB;
|
||||
case PORT_SPEED_64GB:
|
||||
return FDMI_PORT_SPEED_64GB;
|
||||
case PORT_SPEED_128GB:
|
||||
return FDMI_PORT_SPEED_128GB;
|
||||
default:
|
||||
return FDMI_PORT_SPEED_UNKNOWN;
|
||||
}
|
||||
@@ -2620,6 +2706,8 @@ qla2x00_port_speed_capability(uint16_t speed)
|
||||
return PORT_SPEED_32GB;
|
||||
case BIT_7:
|
||||
return PORT_SPEED_64GB;
|
||||
case BIT_6:
|
||||
return PORT_SPEED_128GB;
|
||||
default:
|
||||
return PORT_SPEED_UNKNOWN;
|
||||
}
|
||||
|
||||
@@ -2773,7 +2773,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha)
|
||||
ha->isp_ops->reset_chip(vha);
|
||||
|
||||
/* Check for secure flash support */
|
||||
if (IS_QLA28XX(ha)) {
|
||||
if (IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
if (rd_reg_word(®->mailbox12) & BIT_0)
|
||||
ha->flags.secure_adapter = 1;
|
||||
ql_log(ql_log_info, vha, 0xffff, "Secure Adapter: %s\n",
|
||||
@@ -3733,7 +3733,7 @@ int qla2x00_alloc_fce_trace(scsi_qla_host_t *vha)
|
||||
return -EINVAL;
|
||||
|
||||
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return -EINVAL;
|
||||
|
||||
if (ha->fce) {
|
||||
@@ -3814,6 +3814,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
|
||||
struct req_que *req = ha->req_q_map[0];
|
||||
struct rsp_que *rsp = ha->rsp_q_map[0];
|
||||
struct qla2xxx_fw_dump *fw_dump;
|
||||
size_t req_entry_size = qla_req_entry_size(ha);
|
||||
size_t rsp_entry_size = qla_rsp_entry_size(ha);
|
||||
|
||||
if (ha->fw_dump) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x00bd,
|
||||
@@ -3852,9 +3854,9 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
|
||||
* Resizing must be done at end-of-dump processing.
|
||||
*/
|
||||
mq_size += (ha->max_req_queues - 1) *
|
||||
(req->length * sizeof(request_t));
|
||||
(req->length * req_entry_size);
|
||||
mq_size += (ha->max_rsp_queues - 1) *
|
||||
(rsp->length * sizeof(response_t));
|
||||
(rsp->length * rsp_entry_size);
|
||||
}
|
||||
if (ha->tgt.atio_ring)
|
||||
mq_size += ha->tgt.atio_q_length * sizeof(request_t);
|
||||
@@ -3868,7 +3870,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
|
||||
eft_size = EFT_SIZE;
|
||||
}
|
||||
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
struct fwdt *fwdt = ha->fwdt;
|
||||
uint j;
|
||||
|
||||
@@ -3890,8 +3892,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
|
||||
/* Add space for spare MPI fw dump. */
|
||||
dump_size += ha->fwdt[1].dump_size;
|
||||
} else {
|
||||
req_q_size = req->length * sizeof(request_t);
|
||||
rsp_q_size = rsp->length * sizeof(response_t);
|
||||
req_q_size = req->length * req_entry_size;
|
||||
rsp_q_size = rsp->length * rsp_entry_size;
|
||||
dump_size = offsetof(struct qla2xxx_fw_dump, isp);
|
||||
dump_size += fixed_size + mem_size + req_q_size + rsp_q_size
|
||||
+ eft_size;
|
||||
@@ -3937,7 +3939,8 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
|
||||
"Allocated (%d KB) for firmware dump.\n",
|
||||
dump_size / 1024);
|
||||
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha)) {
|
||||
ha->mpi_fw_dump = (char *)fw_dump +
|
||||
ha->fwdt[1].dump_size;
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
@@ -4194,11 +4197,11 @@ qla24xx_detect_sfp(scsi_qla_host_t *vha)
|
||||
used_nvram = 0;
|
||||
ha->flags.lr_detected = 0;
|
||||
if (IS_BPM_RANGE_CAPABLE(ha) &&
|
||||
(nv->enhanced_features & NEF_LR_DIST_ENABLE)) {
|
||||
(le16_to_cpu(nv->enhanced_features) & NEF_LR_DIST_ENABLE)) {
|
||||
used_nvram = 1;
|
||||
ha->flags.lr_detected = 1;
|
||||
ha->lr_distance =
|
||||
(nv->enhanced_features >> LR_DIST_NV_POS)
|
||||
(le16_to_cpu(nv->enhanced_features) >> LR_DIST_NV_POS)
|
||||
& LR_DIST_NV_MASK;
|
||||
}
|
||||
|
||||
@@ -4478,15 +4481,33 @@ void
|
||||
qla2x00_init_response_q_entries(struct rsp_que *rsp)
|
||||
{
|
||||
uint16_t cnt;
|
||||
response_t *pkt;
|
||||
|
||||
rsp->ring_ptr = rsp->ring;
|
||||
rsp->ring_index = 0;
|
||||
rsp->status_srb = NULL;
|
||||
pkt = rsp->ring_ptr;
|
||||
for (cnt = 0; cnt < rsp->length; cnt++) {
|
||||
pkt->signature = RESPONSE_PROCESSED;
|
||||
pkt++;
|
||||
|
||||
if (rsp->hw && IS_QLA29XX(rsp->hw)) {
|
||||
/*
|
||||
* 29xx uses a 128-byte response-ring stride. The signature
|
||||
* field offset matches response_t, but the entry pitch is
|
||||
* sizeof(struct response_ext); walk via ring_ext_ptr / struct response_ext.
|
||||
*/
|
||||
struct response_ext *pkt;
|
||||
|
||||
rsp->ring_ext_ptr = rsp->ring_ext;
|
||||
pkt = rsp->ring_ext_ptr;
|
||||
for (cnt = 0; cnt < rsp->length; cnt++) {
|
||||
pkt->signature = RESPONSE_PROCESSED;
|
||||
pkt++;
|
||||
}
|
||||
} else {
|
||||
response_t *pkt;
|
||||
|
||||
pkt = rsp->ring_ptr;
|
||||
for (cnt = 0; cnt < rsp->length; cnt++) {
|
||||
pkt->signature = RESPONSE_PROCESSED;
|
||||
pkt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4772,7 +4793,14 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
|
||||
ql_dbg(ql_dbg_init, vha, 0x00fd,
|
||||
"Speed set by user : %s Gbps \n",
|
||||
qla2x00_get_link_speed_str(ha, ha->set_data_rate));
|
||||
icb->firmware_options_3 = cpu_to_le32(ha->set_data_rate << 13);
|
||||
/*
|
||||
* The ICB data-rate field is 3 bits (bits 13-15); rates above
|
||||
* 64G do not fit and would overflow into bit 16 (75 ohm
|
||||
* termination select). Such rates are forced via MBC_DATA_RATE.
|
||||
*/
|
||||
if (ha->set_data_rate <= PORT_SPEED_64GB)
|
||||
icb->firmware_options_3 =
|
||||
cpu_to_le32(ha->set_data_rate << 13);
|
||||
}
|
||||
|
||||
/* PCI posting */
|
||||
@@ -4807,7 +4835,12 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
|
||||
req = ha->req_q_map[que];
|
||||
if (!req || !test_bit(que, ha->req_qid_map))
|
||||
continue;
|
||||
req->out_ptr = (uint16_t *)(req->ring + req->length);
|
||||
if (IS_QLA29XX(ha))
|
||||
req->out_ptr =
|
||||
(uint16_t *)(req->ring_ext + req->length);
|
||||
else
|
||||
req->out_ptr =
|
||||
(uint16_t *)(req->ring + req->length);
|
||||
*req->out_ptr = 0;
|
||||
for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++)
|
||||
req->outstanding_cmds[cnt] = NULL;
|
||||
@@ -4818,13 +4851,19 @@ qla2x00_init_rings(scsi_qla_host_t *vha)
|
||||
req->ring_ptr = req->ring;
|
||||
req->ring_index = 0;
|
||||
req->cnt = req->length;
|
||||
if (IS_QLA29XX(ha))
|
||||
req->ring_ext_ptr = req->ring_ext;
|
||||
}
|
||||
|
||||
for (que = 0; que < ha->max_rsp_queues; que++) {
|
||||
rsp = ha->rsp_q_map[que];
|
||||
if (!rsp || !test_bit(que, ha->rsp_qid_map))
|
||||
continue;
|
||||
rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
|
||||
if (IS_QLA29XX(ha))
|
||||
rsp->in_ptr =
|
||||
(uint16_t *)(rsp->ring_ext + rsp->length);
|
||||
else
|
||||
rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
|
||||
*rsp->in_ptr = 0;
|
||||
/* Initialize response queue entries */
|
||||
if (IS_QLAFX00(ha))
|
||||
@@ -8669,7 +8708,8 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
|
||||
for (i = 0; i < dlen; i++)
|
||||
dcode[i] = swab32(dcode[i]);
|
||||
|
||||
rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
|
||||
rval = qla2x00_load_ram(vha, req->dma, risc_addr,
|
||||
dlen, 0);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x008f,
|
||||
"-> Failed load firmware fragment %u.\n",
|
||||
@@ -8839,7 +8879,7 @@ qla2x00_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
||||
wcode[i] = swab16((__force u32)fwcode[i]);
|
||||
|
||||
rval = qla2x00_load_ram(vha, req->dma, risc_addr,
|
||||
wlen);
|
||||
wlen, 0);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x008a,
|
||||
"Failed to load segment %d of firmware.\n",
|
||||
@@ -8929,7 +8969,8 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
||||
for (i = 0; i < dlen; i++)
|
||||
dcode[i] = swab32((__force u32)fwcode[i]);
|
||||
|
||||
rval = qla2x00_load_ram(vha, req->dma, risc_addr, dlen);
|
||||
rval = qla2x00_load_ram(vha, req->dma, risc_addr,
|
||||
dlen, 0);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"-> Failed load firmware fragment %u.\n",
|
||||
@@ -9128,6 +9169,539 @@ qla81xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int qla29xx_validate_firmware_image(scsi_qla_host_t *vha,
|
||||
__be32 *dword)
|
||||
{
|
||||
if (be32_to_cpu(dword[0]) != LD_FL_HEADER_SIGNATURE) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x0093,
|
||||
"Firmware image Signature does not match (0x%x).\n",
|
||||
be32_to_cpu(dword[0]));
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
if (be32_to_cpu(dword[2]) != LD_FL_HEADER_VERSION) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x0093,
|
||||
"Firmware image Version does not match (0x%x).\n",
|
||||
be32_to_cpu(dword[2]));
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
static int qla29xx_process_rd_image(struct scsi_qla_host *vha,
|
||||
struct fcop_header *header,
|
||||
__be32 *fwcode, int section,
|
||||
uint32_t risc_addr, uint32_t section_size)
|
||||
{
|
||||
int rval = QLA_SUCCESS;
|
||||
uint32_t *dcode = NULL;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct req_que *req = ha->req_q_map[0];
|
||||
int num_segments = 0, segment = 0;
|
||||
int chunks_per_segment = 0, chunk = 0;
|
||||
int is_first_chunk = 0;
|
||||
int is_last_chunk = 0;
|
||||
int is_first_segment = 0;
|
||||
int is_last_segment = 0;
|
||||
int opt = 0;
|
||||
uint32_t size = 0;
|
||||
uint32_t size_remainder = 0;
|
||||
uint32_t seg_size_remainder = 0;
|
||||
int i = 0;
|
||||
|
||||
dcode = (uint32_t *)req->ring;
|
||||
|
||||
if (section == TIM) {
|
||||
if (section_size > req->length * qla_req_entry_size(ha)) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"TIM section too large (0x%x bytes, ring 0x%lx bytes).\n",
|
||||
section_size,
|
||||
req->length * qla_req_entry_size(ha));
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
opt = BIT_15 | BIT_2 | BIT_1 | BIT_0;
|
||||
for (i = 0; i < (section_size >> 2); i++)
|
||||
dcode[i] = swab32((__force u32)fwcode[i]);
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x0098,
|
||||
"TIM : process_rd_image [opt 0x%x]\n", opt);
|
||||
rval = qla2x00_load_ram(vha, req->dma, risc_addr,
|
||||
section_size >> 2, opt);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"-> Failed load TIM\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
} else {
|
||||
size_remainder = section_size;
|
||||
num_segments += (section_size % header->segment_size == 0) ?
|
||||
(section_size / header->segment_size) :
|
||||
(section_size / header->segment_size) + 1;
|
||||
chunks_per_segment =
|
||||
(header->segment_size % CHUNK_SIZE == 0) ?
|
||||
(header->segment_size / CHUNK_SIZE) :
|
||||
(header->segment_size / CHUNK_SIZE) + 1;
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x0098,
|
||||
"num seg 0x%x chunk per seg 0x%x\n",
|
||||
num_segments, chunks_per_segment);
|
||||
|
||||
for (segment = 0; segment < num_segments; segment++) {
|
||||
for (chunk = 0; chunk < chunks_per_segment; chunk++) {
|
||||
is_first_chunk = (chunk == 0);
|
||||
if (chunk == 0) {
|
||||
if (size_remainder >=
|
||||
header->segment_size)
|
||||
seg_size_remainder =
|
||||
header->segment_size;
|
||||
else
|
||||
seg_size_remainder =
|
||||
size_remainder;
|
||||
}
|
||||
|
||||
is_first_segment =
|
||||
(section == ARR1 && segment == 0);
|
||||
is_last_segment =
|
||||
(section == ARR2 &&
|
||||
(segment == (num_segments - 1)));
|
||||
is_last_chunk =
|
||||
(chunk == (chunks_per_segment - 1) ||
|
||||
size_remainder <= CHUNK_SIZE);
|
||||
|
||||
if (seg_size_remainder < CHUNK_SIZE)
|
||||
size = seg_size_remainder % CHUNK_SIZE;
|
||||
else
|
||||
size = CHUNK_SIZE;
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x0098,
|
||||
"[%d]chunk 0x%x segment 0x%x first_segment 0x%x first_chunk 0x%x last_segment 0x%x last_chunk 0x%x\n",
|
||||
__LINE__, chunk, segment,
|
||||
is_first_segment, is_first_chunk,
|
||||
is_last_segment, is_last_chunk);
|
||||
|
||||
opt = BIT_2;
|
||||
if (is_first_chunk)
|
||||
opt |= BIT_0;
|
||||
if (is_last_chunk)
|
||||
opt |= BIT_1;
|
||||
if (is_first_segment)
|
||||
opt |= BIT_3;
|
||||
if (is_last_segment)
|
||||
opt |= BIT_4;
|
||||
|
||||
for (i = 0; i < (size >> 2); i++)
|
||||
dcode[i] =
|
||||
swab32((__force u32)fwcode[i]);
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x0098,
|
||||
"ARR[0x%x] : opt 0x%x\n", size, opt);
|
||||
rval = qla2x00_load_ram(vha, req->dma,
|
||||
risc_addr,
|
||||
size >> 2, opt);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"-> Failed load ram\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
fwcode += size >> 2;
|
||||
size_remainder -= size;
|
||||
seg_size_remainder -= size;
|
||||
if (size_remainder == 0)
|
||||
break;
|
||||
}
|
||||
risc_addr += header->segment_size >> 2;
|
||||
}
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int
|
||||
qla29xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
||||
{
|
||||
int rval;
|
||||
struct fcop_header *header;
|
||||
uint32_t *dcode = NULL;
|
||||
struct fw_blob *blob;
|
||||
__be32 *fwcode, *array1_addr, *array3_addr;
|
||||
uint templates;
|
||||
uint32_t array_size, risc_attr = 0;
|
||||
ulong i;
|
||||
uint j;
|
||||
ulong dlen, array3_offset;
|
||||
size_t max_dwords;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct fwdt *fwdt = ha->fwdt;
|
||||
|
||||
header = vmalloc(sizeof(*header));
|
||||
if (!header)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x0090,
|
||||
"-> FW: Loading via request-firmware.\n");
|
||||
|
||||
blob = qla2x00_request_firmware(vha);
|
||||
if (!blob) {
|
||||
ql_log(ql_log_warn, vha, 0x0092,
|
||||
"-> Firmware file not found.\n");
|
||||
vfree(header);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
fwcode = (__force __be32 *)blob->fw->data;
|
||||
|
||||
if (blob->fw->size < sizeof(*header)) {
|
||||
ql_log(ql_log_fatal, vha, 0x0093,
|
||||
"Firmware image too small (%zu bytes, need %zu).\n",
|
||||
blob->fw->size, sizeof(*header));
|
||||
vfree(header);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
rval = qla29xx_validate_firmware_image(vha, fwcode);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_fatal, vha, 0x0093,
|
||||
"Unable to verify integrity of firmware image\n");
|
||||
vfree(header);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
/* byte-swap big-endian firmware header to CPU endian */
|
||||
for (i = 0; i < sizeof(*header) / sizeof(__be32); i++)
|
||||
((uint32_t *)header)[i] = be32_to_cpu(fwcode[i]);
|
||||
|
||||
/*
|
||||
* Section lengths are dword counts from the firmware image. Reject
|
||||
* values that would overflow the u32 fields on conversion to bytes
|
||||
* (<< 2) or that exceed the image, before using them below.
|
||||
*/
|
||||
max_dwords = blob->fw->size >> 2;
|
||||
if (header->header_length > max_dwords ||
|
||||
header->tim_length > max_dwords ||
|
||||
header->array1_length > max_dwords ||
|
||||
header->array2_length > max_dwords ||
|
||||
header->array3_length > max_dwords ||
|
||||
header->array4_length > max_dwords) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"FW image has invalid section length.\n");
|
||||
goto img_corrupt;
|
||||
}
|
||||
|
||||
header->header_length <<= 2;
|
||||
header->tim_length <<= 2;
|
||||
header->array1_length <<= 2;
|
||||
header->array2_length <<= 2;
|
||||
header->array3_length <<= 2;
|
||||
header->array4_length <<= 2;
|
||||
|
||||
if (!header->segment_size) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"FW image has zero segment_size.\n");
|
||||
goto img_corrupt;
|
||||
}
|
||||
|
||||
{
|
||||
size_t fw_size = blob->fw->size;
|
||||
size_t offset;
|
||||
|
||||
/* TIM */
|
||||
offset = header->header_length;
|
||||
if (offset + header->tim_length > fw_size) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"FW image too small for TIM (%#zx > %#zx).\n",
|
||||
offset + header->tim_length, fw_size);
|
||||
goto img_corrupt;
|
||||
}
|
||||
rval = qla29xx_process_rd_image(vha, header,
|
||||
(__be32 *)((char *)fwcode + offset),
|
||||
TIM, TIM_DEST_ADDR, header->tim_length);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"-> Failed load TIM\n");
|
||||
goto img_corrupt;
|
||||
}
|
||||
|
||||
/* Array 1 */
|
||||
offset += header->tim_length;
|
||||
if (offset + header->array1_length > fw_size) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"FW image too small for Arr1 (%#zx > %#zx).\n",
|
||||
offset + header->array1_length, fw_size);
|
||||
goto img_corrupt;
|
||||
}
|
||||
rval = qla29xx_process_rd_image(vha, header,
|
||||
(__be32 *)((char *)fwcode + offset),
|
||||
ARR1, header->array1_destination_addr,
|
||||
header->array1_length);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"-> Failed load Arr1\n");
|
||||
goto img_corrupt;
|
||||
}
|
||||
|
||||
/* Array 2 */
|
||||
offset += header->array1_length;
|
||||
if (offset + header->array2_length > fw_size) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"FW image too small for Arr2 (%#zx > %#zx).\n",
|
||||
offset + header->array2_length, fw_size);
|
||||
goto img_corrupt;
|
||||
}
|
||||
rval = qla29xx_process_rd_image(vha, header,
|
||||
(__be32 *)((char *)fwcode + offset),
|
||||
ARR2, header->array2_destination_addr,
|
||||
header->array2_length);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"-> Failed load Arr2\n");
|
||||
goto img_corrupt;
|
||||
}
|
||||
|
||||
/* Array 3: FW_DUMP template */
|
||||
if (offset + 10 * sizeof(__be32) > fw_size) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"FW image too small for risc_attr.\n");
|
||||
goto img_corrupt;
|
||||
}
|
||||
array1_addr = (__be32 *)((char *)fwcode +
|
||||
header->header_length +
|
||||
header->tim_length);
|
||||
risc_attr = be32_to_cpu(array1_addr[9]);
|
||||
}
|
||||
templates = (risc_attr & BIT_9) ? 2 : 1;
|
||||
ql_dbg(ql_dbg_init, vha, 0x0160,
|
||||
"-> templates = %u\n", templates);
|
||||
|
||||
array3_offset = header->header_length + header->tim_length +
|
||||
header->array1_length + header->array2_length;
|
||||
if (array3_offset > blob->fw->size) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"FW image too small for Arr3 (%#lx > %#zx).\n",
|
||||
array3_offset, blob->fw->size);
|
||||
goto img_corrupt;
|
||||
}
|
||||
|
||||
array3_addr = (__be32 *)(((char *)fwcode) + array3_offset);
|
||||
for (j = 0; j < templates; j++, fwdt++) {
|
||||
vfree(fwdt->template);
|
||||
fwdt->template = NULL;
|
||||
fwdt->length = 0;
|
||||
|
||||
if ((char *)&array3_addr[7] >
|
||||
(char *)blob->fw->data + blob->fw->size) {
|
||||
ql_log(ql_log_warn, vha, 0x0169,
|
||||
"-> fwdt%u template header exceeds firmware blob.\n",
|
||||
j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
array_size = be32_to_cpu(array3_addr[2]);
|
||||
ql_dbg(ql_dbg_init, vha, 0x0161,
|
||||
"-> fwdt%u template array at %p (%#x dwords)\n",
|
||||
j, array3_addr, array_size);
|
||||
|
||||
if (!array_size || !~array_size || array_size <= 8) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x0162,
|
||||
"-> fwdt%u failed to read array\n", j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
array3_addr += 7;
|
||||
array_size -= 8;
|
||||
|
||||
if ((char *)&array3_addr[array_size] >
|
||||
(char *)blob->fw->data + blob->fw->size) {
|
||||
ql_log(ql_log_warn, vha, 0x0163,
|
||||
"-> fwdt%u template array exceeds firmware blob.\n",
|
||||
j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x0163,
|
||||
"-> fwdt%u template allocate template %#x words...\n",
|
||||
j, array_size);
|
||||
fwdt->template = vmalloc_array(array_size, sizeof(*dcode));
|
||||
if (!fwdt->template) {
|
||||
ql_log(ql_log_warn, vha, 0x0164,
|
||||
"-> fwdt%u failed allocate template.\n", j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
dcode = fwdt->template;
|
||||
for (i = 0; i < array_size; i++)
|
||||
dcode[i] = (__force u32)array3_addr[i];
|
||||
|
||||
if (!qla27xx_fwdt_template_valid(dcode)) {
|
||||
ql_log(ql_log_warn, vha, 0x0165,
|
||||
"-> fwdt%u failed template validate\n", j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
dlen = qla27xx_fwdt_template_size(dcode);
|
||||
ql_dbg(ql_dbg_init, vha, 0x0166,
|
||||
"-> fwdt%u template size %#lx bytes (%#lx words)\n",
|
||||
j, dlen, dlen / sizeof(*dcode));
|
||||
if (dlen > array_size * sizeof(*dcode)) {
|
||||
ql_log(ql_log_warn, vha, 0x0167,
|
||||
"-> fwdt%u template exceeds array (%-lu bytes)\n",
|
||||
j, dlen - array_size * sizeof(*dcode));
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fwdt->length = dlen;
|
||||
ql_dbg(ql_dbg_init, vha, 0x0168,
|
||||
"-> fwdt%u loaded template ok\n", j);
|
||||
|
||||
array3_addr += array_size + 1;
|
||||
}
|
||||
vfree(header);
|
||||
return QLA_SUCCESS;
|
||||
|
||||
failed:
|
||||
vfree(fwdt->template);
|
||||
fwdt->template = NULL;
|
||||
fwdt->length = 0;
|
||||
img_corrupt:
|
||||
vfree(header);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static int
|
||||
qla29xx_load_fw_template(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct fwdt *fwdt = ha->fwdt;
|
||||
uint templates = 1;
|
||||
void *fw_dump_tmplt;
|
||||
uint32_t *dcode;
|
||||
void *buf = NULL;
|
||||
uint32_t len;
|
||||
uint32_t template_size;
|
||||
uint j = 0;
|
||||
int rval = 0;
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x01bf,
|
||||
"-> templates = %u fw_dump_tmplt_len = 0x%x\n",
|
||||
templates, ha->fw_dump_tmplt_len);
|
||||
|
||||
if (!ha->fw_dump_tmplt_len) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x01bf,
|
||||
"no fw dump template available\n");
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
fw_dump_tmplt = kzalloc(ha->fw_dump_tmplt_len, GFP_KERNEL);
|
||||
if (!fw_dump_tmplt) {
|
||||
ql_log(ql_log_info, vha, 0x0013,
|
||||
"Unable to allocate memory\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
buf = qla29xx_read_optrom_data(vha, FLT_REG_FW_DUMP_TMPLT, 0,
|
||||
fw_dump_tmplt, 0,
|
||||
ha->fw_dump_tmplt_len);
|
||||
if (!buf) {
|
||||
ql_log(ql_log_info, vha, 0x0013,
|
||||
"Unable to read fw dump temp info.\n");
|
||||
goto free_fw_dump;
|
||||
}
|
||||
|
||||
ql_dump_buffer(ql_dbg_init, vha, 0x006b, fw_dump_tmplt,
|
||||
min_t(uint32_t, ha->fw_dump_tmplt_len, 1024));
|
||||
|
||||
for (j = 0; j < templates; j++, fwdt++) {
|
||||
vfree(fwdt->template);
|
||||
fwdt->template = NULL;
|
||||
fwdt->length = 0;
|
||||
|
||||
template_size = le32_to_cpu(((__le32 *)fw_dump_tmplt)[2]);
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x0161,
|
||||
"-> fwdt%u template array at %p (0x%x bytes)\n",
|
||||
j, fw_dump_tmplt, template_size);
|
||||
|
||||
if (!template_size || !~template_size ||
|
||||
template_size > ha->fw_dump_tmplt_len) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x0162,
|
||||
"-> fwdt%u failed to read array\n", j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fwdt->template = vmalloc(template_size);
|
||||
if (!fwdt->template) {
|
||||
ql_log(ql_log_warn, vha, 0x0164,
|
||||
"-> fwdt%u failed allocate template.\n", j);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
dcode = fwdt->template;
|
||||
memcpy((char *)dcode, (char *)fw_dump_tmplt, template_size);
|
||||
|
||||
if (!qla27xx_fwdt_template_valid(dcode)) {
|
||||
ql_log(ql_log_warn, vha, 0x0165,
|
||||
"-> fwdt%u failed template validate (rval %x)\n",
|
||||
j, rval);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
len = qla27xx_fwdt_template_size(dcode);
|
||||
if (len > template_size) {
|
||||
ql_log(ql_log_warn, vha, 0x0167,
|
||||
"-> fwdt%u template exceeds array (%-u bytes)\n",
|
||||
j, len - template_size);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
fwdt->length = len;
|
||||
}
|
||||
|
||||
kfree(fw_dump_tmplt);
|
||||
return QLA_SUCCESS;
|
||||
|
||||
failed:
|
||||
if (fwdt->template) {
|
||||
vfree(fwdt->template);
|
||||
fwdt->template = NULL;
|
||||
fwdt->length = 0;
|
||||
}
|
||||
free_fw_dump:
|
||||
kfree(fw_dump_tmplt);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
int
|
||||
qla29xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
|
||||
{
|
||||
int rval;
|
||||
|
||||
*srisc_addr = 0x100000;
|
||||
|
||||
if (ql2xfwloadbin == 2) {
|
||||
rval = qla29xx_load_risc_blob(vha, srisc_addr);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_fatal, vha, 0x019e,
|
||||
"Failed to load firmware from file.\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
} else {
|
||||
rval = qla28xx_load_flash_firmware(vha);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_fatal, vha, 0x019e,
|
||||
"Failed to load flash firmware.\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
rval = qla29xx_load_fw_template(vha);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x01bd,
|
||||
"failed to read firmware template\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
void
|
||||
qla2x00_try_to_stop_firmware(scsi_qla_host_t *vha)
|
||||
{
|
||||
@@ -9306,35 +9880,98 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
|
||||
if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
|
||||
ha->vpd_size = FA_VPD_SIZE_82XX;
|
||||
|
||||
if (IS_QLA28XX(ha) || IS_QLA27XX(ha))
|
||||
qla28xx_get_aux_images(vha, &active_regions);
|
||||
|
||||
/* Get VPD data into cache */
|
||||
ha->vpd = ha->nvram + VPD_OFFSET;
|
||||
|
||||
faddr = ha->flt_region_vpd;
|
||||
if (IS_QLA28XX(ha)) {
|
||||
if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
|
||||
faddr = ha->flt_region_vpd_sec;
|
||||
if (IS_QLA29XX(ha)) {
|
||||
uint16_t fw_options = 0, r_code;
|
||||
uint32_t vpd_r[] = {FLT_REG_VPD_0, FLT_REG_VPD_1,
|
||||
FLT_REG_VPD_2, FLT_REG_VPD_3};
|
||||
uint32_t nvram_r[] = {FLT_REG_NVRAM_0, FLT_REG_NVRAM_1,
|
||||
FLT_REG_NVRAM_2, FLT_REG_NVRAM_3};
|
||||
void *buf;
|
||||
|
||||
BUILD_BUG_ON((VPD_OFFSET + FA_NVRAM_VPD_SIZE +
|
||||
sizeof(struct qla_flash_memo_block)) >
|
||||
MAX_NVRAM_SIZE);
|
||||
|
||||
ha->fiv = (struct qla_flash_memo_block *)
|
||||
((char *)ha->vpd + ha->vpd_size);
|
||||
|
||||
buf = qla29xx_read_optrom_data(vha, FLT_REG_FMB_PRI,
|
||||
fw_options, ha->fiv, 0,
|
||||
sizeof(struct qla_flash_memo_block));
|
||||
if (!buf) {
|
||||
ql_log(ql_log_info, vha, 0x01be,
|
||||
"Unable to read Flash Image Version.\n");
|
||||
} else if (ha->fiv->signature != QLFC_FMB_SIG) {
|
||||
ql_log(ql_log_warn, vha, 0x01bf,
|
||||
"Invalid FMB signature %#x, expected %#x.\n",
|
||||
le32_to_cpu(ha->fiv->signature),
|
||||
le32_to_cpu(QLFC_FMB_SIG));
|
||||
ha->fiv = NULL;
|
||||
} else {
|
||||
ql_log(ql_log_info, vha, 0x0024,
|
||||
"Flash Image Version %u.%02u.%02u\n",
|
||||
ha->fiv->mbi_ver.major,
|
||||
ha->fiv->mbi_ver.minor,
|
||||
ha->fiv->mbi_ver.sub);
|
||||
}
|
||||
|
||||
if (ha->port_no >= ARRAY_SIZE(vpd_r)) {
|
||||
ql_log(ql_log_warn, vha, 0x002e,
|
||||
"Invalid port number %u, skipping VPD/NVRAM read.\n",
|
||||
ha->port_no);
|
||||
goto out_29xx;
|
||||
}
|
||||
|
||||
r_code = vpd_r[ha->port_no];
|
||||
buf = qla29xx_read_optrom_data(vha, r_code, fw_options,
|
||||
ha->vpd, 0, ha->vpd_size);
|
||||
if (!buf)
|
||||
ql_log(ql_log_info, vha, 0x002d,
|
||||
"Unable to read VPD info.\n");
|
||||
|
||||
r_code = nvram_r[ha->port_no];
|
||||
buf = qla29xx_read_optrom_data(vha, r_code, fw_options,
|
||||
ha->nvram, 0, ha->nvram_size);
|
||||
if (!buf)
|
||||
ql_log(ql_log_info, vha, 0x0013,
|
||||
"Unable to read nvram config info.\n");
|
||||
} else {
|
||||
if (IS_QLA28XX(ha) || IS_QLA27XX(ha))
|
||||
qla28xx_get_aux_images(vha, &active_regions);
|
||||
|
||||
faddr = ha->flt_region_vpd;
|
||||
if (IS_QLA28XX(ha)) {
|
||||
if (active_regions.aux.vpd_nvram ==
|
||||
QLA27XX_SECONDARY_IMAGE)
|
||||
faddr = ha->flt_region_vpd_sec;
|
||||
ql_dbg(ql_dbg_init, vha, 0x0110,
|
||||
"Loading %s nvram image.\n",
|
||||
active_regions.aux.vpd_nvram ==
|
||||
QLA27XX_PRIMARY_IMAGE ?
|
||||
"primary" : "secondary");
|
||||
}
|
||||
ha->isp_ops->read_optrom(vha, ha->vpd, faddr << 2,
|
||||
ha->vpd_size);
|
||||
|
||||
/* Get NVRAM data into cache and calculate checksum. */
|
||||
faddr = ha->flt_region_nvram;
|
||||
if (IS_QLA28XX(ha)) {
|
||||
if (active_regions.aux.vpd_nvram ==
|
||||
QLA27XX_SECONDARY_IMAGE)
|
||||
faddr = ha->flt_region_nvram_sec;
|
||||
}
|
||||
ql_dbg(ql_dbg_init, vha, 0x0110,
|
||||
"Loading %s nvram image.\n",
|
||||
active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
|
||||
"primary" : "secondary");
|
||||
ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2,
|
||||
ha->nvram_size);
|
||||
}
|
||||
ha->isp_ops->read_optrom(vha, ha->vpd, faddr << 2, ha->vpd_size);
|
||||
|
||||
/* Get NVRAM data into cache and calculate checksum. */
|
||||
faddr = ha->flt_region_nvram;
|
||||
if (IS_QLA28XX(ha)) {
|
||||
if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
|
||||
faddr = ha->flt_region_nvram_sec;
|
||||
}
|
||||
ql_dbg(ql_dbg_init, vha, 0x0110,
|
||||
"Loading %s nvram image.\n",
|
||||
active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
|
||||
"primary" : "secondary");
|
||||
ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, ha->nvram_size);
|
||||
|
||||
out_29xx:
|
||||
dptr = (__force __le32 *)nv;
|
||||
for (cnt = 0, chksum = 0; cnt < ha->nvram_size >> 2; cnt++, dptr++)
|
||||
chksum += le32_to_cpu(*dptr);
|
||||
@@ -9386,7 +10023,10 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
|
||||
nv->login_timeout = cpu_to_le16(0);
|
||||
nv->firmware_options_1 =
|
||||
cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1);
|
||||
nv->firmware_options_2 = cpu_to_le32(2 << 4);
|
||||
if (IS_QLA29XX(ha))
|
||||
nv->firmware_options_2 = cpu_to_le32(BIT_4);
|
||||
else
|
||||
nv->firmware_options_2 = cpu_to_le32(BIT_5);
|
||||
nv->firmware_options_2 |= cpu_to_le32(BIT_12);
|
||||
nv->firmware_options_3 = cpu_to_le32(2 << 13);
|
||||
nv->host_p = cpu_to_le32(BIT_11|BIT_10);
|
||||
@@ -9468,9 +10108,13 @@ 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)
|
||||
/* SCM Enabled in NVRAM */
|
||||
if (IS_QLA29XX(ha) || IS_QLA28XX(ha) || IS_QLA27XX(ha)) {
|
||||
if ((le16_to_cpu(nv->enhanced_features) & BIT_7) == 0) {
|
||||
ql_log(ql_log_info, vha, 0x0062,
|
||||
"USCM enabled in NVRAM\n");
|
||||
ha->flags.scm_supported_a = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set host adapter parameters. */
|
||||
@@ -9546,7 +10190,8 @@ qla81xx_nvram_config(scsi_qla_host_t *vha)
|
||||
|
||||
/* if not running MSI-X we need handshaking on interrupts */
|
||||
if (!vha->hw->flags.msix_enabled &&
|
||||
(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)))
|
||||
(IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha)))
|
||||
icb->firmware_options_2 |= cpu_to_le32(BIT_22);
|
||||
|
||||
/* Enable ZIO. */
|
||||
|
||||
@@ -54,6 +54,90 @@ qla2x00_debounce_register(volatile __le16 __iomem *addr)
|
||||
return (first);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_calc_iocbs() - Determine number of Command-Type and Continuation
|
||||
* IOCBs to allocate for the 29xx extended (128-byte) IOCB ring.
|
||||
* @vha: HA context
|
||||
* @dsds: number of data segment descriptors needed
|
||||
* @iocb_dsds: number of DSDs embedded in the first (command) IOCB. The
|
||||
* remaining DSDs ride on Continuation Type 1 Ext IOCBs which hold
|
||||
* NUM_CONT1_DSDS (10) each.
|
||||
*
|
||||
* Returns the total number of IOCB entries needed to carry @dsds.
|
||||
*/
|
||||
static inline uint16_t
|
||||
qla29xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds, uint8_t iocb_dsds)
|
||||
{
|
||||
uint16_t iocbs = 1;
|
||||
|
||||
if (dsds > iocb_dsds) {
|
||||
iocbs += (dsds - iocb_dsds) / NUM_CONT1_DSDS;
|
||||
if ((dsds - iocb_dsds) % NUM_CONT1_DSDS)
|
||||
iocbs++;
|
||||
}
|
||||
return iocbs;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla_req_entry_size() - request-ring entry stride.
|
||||
* @ha: HBA pointer
|
||||
*
|
||||
* Returns sizeof(struct request_ext) (128) on 29xx, sizeof(request_t) (64)
|
||||
* everywhere else.
|
||||
*/
|
||||
static inline size_t
|
||||
qla_req_entry_size(struct qla_hw_data *ha)
|
||||
{
|
||||
return IS_QLA29XX(ha) ? sizeof(struct request_ext) : sizeof(request_t);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla_rsp_entry_size() - response-ring entry stride.
|
||||
* @ha: HBA pointer
|
||||
*
|
||||
* Counterpart of qla_req_entry_size() for the response ring.
|
||||
*/
|
||||
static inline size_t
|
||||
qla_rsp_entry_size(struct qla_hw_data *ha)
|
||||
{
|
||||
return IS_QLA29XX(ha) ? sizeof(struct response_ext) : sizeof(response_t);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla_sts_cont_data_size() - status-continuation IOCB data payload size.
|
||||
* @ha: HBA pointer
|
||||
*
|
||||
* sts_cont_entry_t and struct sts_cont_entry_ext share the same header and
|
||||
* data offset; only the trailing data[] size differs (60 vs 124 bytes).
|
||||
* Returns that size so callers need not branch on the adapter type.
|
||||
*/
|
||||
static inline u32
|
||||
qla_sts_cont_data_size(struct qla_hw_data *ha)
|
||||
{
|
||||
return IS_QLA29XX(ha) ?
|
||||
sizeof_field(struct sts_cont_entry_ext, data) :
|
||||
sizeof_field(sts_cont_entry_t, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla_logio_set_vp_index() - write vp_index into a login/logout IOCB.
|
||||
* @ha: HBA pointer
|
||||
* @pkt: logio IOCB (logio_entry_24xx or logio_entry_24xx_ext)
|
||||
* @vp_idx: virtual port index
|
||||
*
|
||||
* vp_index widens from u8 (logio_entry_24xx) to __le16
|
||||
* (logio_entry_24xx_ext) on 29xx; write the field at the right width.
|
||||
*/
|
||||
static inline void
|
||||
qla_logio_set_vp_index(struct qla_hw_data *ha, void *pkt, u16 vp_idx)
|
||||
{
|
||||
if (IS_QLA29XX(ha))
|
||||
((struct logio_entry_24xx_ext *)pkt)->vp_index =
|
||||
cpu_to_le16(vp_idx);
|
||||
else
|
||||
((struct logio_entry_24xx *)pkt)->vp_index = vp_idx;
|
||||
}
|
||||
|
||||
static inline void
|
||||
qla2x00_poll(struct rsp_que *rsp)
|
||||
{
|
||||
@@ -358,17 +442,132 @@ static inline void
|
||||
qla_83xx_start_iocbs(struct qla_qpair *qpair)
|
||||
{
|
||||
struct req_que *req = qpair->req;
|
||||
struct qla_hw_data *ha = qpair->vha->hw;
|
||||
|
||||
/*
|
||||
* 29xx uses the 128-byte-strided extended request ring; advance the
|
||||
* matching ring_ext_ptr so the next IOCB allocator sees the correct
|
||||
* slot. All other 83xx-family generations (83xx/27xx/28xx) keep the
|
||||
* 64-byte ring_ptr.
|
||||
*/
|
||||
req->ring_index++;
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ptr = req->ring;
|
||||
} else
|
||||
req->ring_ptr++;
|
||||
if (IS_QLA29XX(ha)) {
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ext_ptr = req->ring_ext;
|
||||
} else {
|
||||
req->ring_ext_ptr++;
|
||||
}
|
||||
} else {
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ptr = req->ring;
|
||||
} else {
|
||||
req->ring_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
wrt_reg_dword(req->req_q_in, req->ring_index);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla_rsp_ring_advance() - Advance the response queue consumer pointer
|
||||
* to the next IOCB slot, handling both 24xx (64-byte) and 29xx (128-byte)
|
||||
* ring strides.
|
||||
*
|
||||
* On 29xx, ring_ext_ptr is the authoritative slot pointer (correct 128-byte
|
||||
* pitch) and ring_ptr is kept in sync as a response_t view of the same slot
|
||||
* so existing 24xx-shaped reads (rsp->ring_ptr->signature,
|
||||
* (struct sts_entry_24xx *)rsp->ring_ptr, etc.) keep working unchanged; the
|
||||
* first 64 bytes of struct response_ext are layout-compatible with response_t.
|
||||
*/
|
||||
static inline void
|
||||
qla_rsp_ring_advance(struct rsp_que *rsp)
|
||||
{
|
||||
rsp->ring_index++;
|
||||
if (rsp->ring_index == rsp->length) {
|
||||
rsp->ring_index = 0;
|
||||
rsp->ring_ptr = rsp->ring;
|
||||
if (rsp->hw && IS_QLA29XX(rsp->hw))
|
||||
rsp->ring_ext_ptr = rsp->ring_ext;
|
||||
} else if (rsp->hw && IS_QLA29XX(rsp->hw)) {
|
||||
rsp->ring_ext_ptr++;
|
||||
rsp->ring_ptr = (response_t *)rsp->ring_ext_ptr;
|
||||
} else {
|
||||
rsp->ring_ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla_req_ring_slot() - return the current request-ring producer slot.
|
||||
* @ha: HBA pointer
|
||||
* @req: request queue
|
||||
*
|
||||
* On 29xx the firmware-visible ring uses 128-byte-strided entries
|
||||
* referenced by ring_ext_ptr; on earlier adapters the 64-byte ring
|
||||
* referenced by ring_ptr is used. The returned pointer is
|
||||
* layout-compatible with request_t for common header writes; callers
|
||||
* needing 29xx-specific fields should cast to struct request_ext.
|
||||
*/
|
||||
static inline void *
|
||||
qla_req_ring_slot(struct qla_hw_data *ha, struct req_que *req)
|
||||
{
|
||||
return IS_QLA29XX(ha) ? (void *)req->ring_ext_ptr
|
||||
: (void *)req->ring_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla_req_ring_advance() - advance request-ring producer pointer.
|
||||
* @ha: HBA pointer
|
||||
* @req: request queue
|
||||
*
|
||||
* Mirrors qla_rsp_ring_advance(). Does NOT publish the new producer
|
||||
* index to firmware; callers that need to do so should follow with a
|
||||
* wrt_reg_dword or qla_83xx_start_iocbs().
|
||||
*/
|
||||
static inline void
|
||||
qla_req_ring_advance(struct qla_hw_data *ha, struct req_que *req)
|
||||
{
|
||||
req->ring_index++;
|
||||
if (IS_QLA29XX(ha)) {
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ext_ptr = req->ring_ext;
|
||||
} else {
|
||||
req->ring_ext_ptr++;
|
||||
}
|
||||
} else {
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ptr = req->ring;
|
||||
} else {
|
||||
req->ring_ptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla_rsp_ring_rewind_to() - Restore the response queue consumer pointer
|
||||
* to a previously-observed slot (used when we need to defer processing an
|
||||
* IOCB whose continuation entries have not yet arrived).
|
||||
* @rsp: response queue
|
||||
* @pkt: 64-byte view of the slot to rewind to (captured from a prior read
|
||||
* of rsp->ring_ptr)
|
||||
* @idx: matching ring_index value (also captured before the advance)
|
||||
*
|
||||
* On 29xx, pkt was originally obtained as (response_t *)rsp->ring_ext_ptr,
|
||||
* so casting back to struct response_ext * recovers the 128-byte-stride slot
|
||||
* pointer.
|
||||
*/
|
||||
static inline void
|
||||
qla_rsp_ring_rewind_to(struct rsp_que *rsp, response_t *pkt, uint16_t idx)
|
||||
{
|
||||
rsp->ring_ptr = pkt;
|
||||
rsp->ring_index = idx;
|
||||
if (rsp->hw && IS_QLA29XX(rsp->hw))
|
||||
rsp->ring_ext_ptr = (struct response_ext *)pkt;
|
||||
}
|
||||
|
||||
static inline int
|
||||
qla2xxx_get_fc4_priority(struct scsi_qla_host *vha)
|
||||
{
|
||||
@@ -638,3 +837,76 @@ static inline bool val_is_in_range(u32 val, u32 start, u32 end)
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Common fields extracted from FWI2 status IOCBs. Populated once so
|
||||
* callers avoid duplicated IS_QLA29XX() branches for every field access.
|
||||
*/
|
||||
struct qla_sts_fwi2 {
|
||||
u8 *data;
|
||||
u32 data_sz;
|
||||
u16 scsi_status;
|
||||
u16 sts_qual;
|
||||
u32 sense_len;
|
||||
u32 rsp_data_len;
|
||||
u32 rsp_residual_count;
|
||||
};
|
||||
|
||||
static inline void
|
||||
qla_sts_fwi2_extract(struct qla_hw_data *ha, void *pkt,
|
||||
struct qla_sts_fwi2 *sf)
|
||||
{
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct sts_entry_24xx_ext *s = pkt;
|
||||
|
||||
sf->scsi_status = le16_to_cpu(s->u2.scsi_status);
|
||||
sf->sts_qual = le16_to_cpu(s->u2.retry_delay_timer);
|
||||
sf->sense_len = le32_to_cpu(s->u2.sense_len);
|
||||
sf->rsp_data_len = le32_to_cpu(s->u2.rsp_data_len_ndma);
|
||||
sf->rsp_residual_count = le32_to_cpu(s->u2.rsp_residual_count);
|
||||
sf->data = s->u2.data;
|
||||
sf->data_sz = sizeof(s->u2.data);
|
||||
host_to_fcp_swap(s->u2.data, sizeof(s->u2.data));
|
||||
host_to_fcp_swap(s->act_dif, sizeof(s->act_dif));
|
||||
host_to_fcp_swap(s->exp_dif, sizeof(s->exp_dif));
|
||||
} else {
|
||||
struct sts_entry_24xx *s = pkt;
|
||||
|
||||
sf->scsi_status = le16_to_cpu(s->scsi_status);
|
||||
sf->sts_qual = le16_to_cpu(s->status_qualifier);
|
||||
sf->sense_len = le32_to_cpu(s->sense_len);
|
||||
sf->rsp_data_len = le32_to_cpu(s->rsp_data_len);
|
||||
sf->rsp_residual_count = le32_to_cpu(s->rsp_residual_count);
|
||||
sf->data = s->data;
|
||||
sf->data_sz = sizeof(s->data);
|
||||
host_to_fcp_swap(s->data, sizeof(s->data));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* qla_els_set_vp_sof() - write the vp_index / sof_type pair into an ELS
|
||||
* pass-through IOCB (els_entry_24xx{,_ext}).
|
||||
*
|
||||
* Both layouts have the same 16-bit slot at offset 14, but it is encoded
|
||||
* differently:
|
||||
* - 24xx: separate u8 vp_index + u8 sof_type with EST_SOFI3 (1 << 4)
|
||||
* - 29xx: __le16 vp_index_sof with bits [8:0]=VP index, [15:12]=SOF type
|
||||
* and ELS_EXT_EST_SOFI3
|
||||
* so this is the single point in the driver that knows about that
|
||||
* encoding split.
|
||||
*/
|
||||
static inline void
|
||||
qla_els_set_vp_sof(struct scsi_qla_host *vha, void *pkt, u16 vp_idx)
|
||||
{
|
||||
if (IS_QLA29XX(vha->hw)) {
|
||||
struct els_entry_24xx_ext *ext = pkt;
|
||||
|
||||
ext->vp_index_sof =
|
||||
qla_ext_build_vp_sof(vp_idx, ELS_EXT_EST_SOFI3);
|
||||
} else {
|
||||
struct els_entry_24xx *e = pkt;
|
||||
|
||||
e->vp_index = vp_idx;
|
||||
e->sof_type = EST_SOFI3;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -618,7 +618,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp)
|
||||
|
||||
int
|
||||
qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
|
||||
uint32_t risc_code_size)
|
||||
uint32_t risc_code_size, int opt)
|
||||
{
|
||||
int rval;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
@@ -651,7 +651,14 @@ qla2x00_load_ram(scsi_qla_host_t *vha, dma_addr_t req_dma, uint32_t risc_addr,
|
||||
mcp->out_mb |= MBX_4;
|
||||
}
|
||||
|
||||
mcp->in_mb = MBX_1|MBX_0;
|
||||
if (IS_QLA29XX(ha)) {
|
||||
mcp->mb[9] = opt;
|
||||
mcp->out_mb |= MBX_9;
|
||||
mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
} else {
|
||||
mcp->in_mb = MBX_1|MBX_0;
|
||||
}
|
||||
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
@@ -692,6 +699,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
|
||||
{
|
||||
int rval;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct nvram_81xx *nv = ha->nvram;
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
u8 semaphore = 0;
|
||||
@@ -720,14 +728,13 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
|
||||
ha->lr_distance << LR_DIST_FW_POS;
|
||||
}
|
||||
|
||||
if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha)))
|
||||
if (ql2xnvmeenable && (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)))
|
||||
mcp->mb[4] |= NVME_ENABLE_FLAG;
|
||||
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
struct nvram_81xx *nv = ha->nvram;
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
/* set minimum speed if specified in nvram */
|
||||
if (nv->min_supported_speed >= 2 &&
|
||||
nv->min_supported_speed <= 5) {
|
||||
nv->min_supported_speed <= 7) {
|
||||
mcp->mb[4] |= BIT_4;
|
||||
mcp->mb[11] |= nv->min_supported_speed & 0xF;
|
||||
mcp->out_mb |= MBX_11;
|
||||
@@ -765,7 +772,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
|
||||
if (rval != QLA_SUCCESS) {
|
||||
if (IS_QLA28XX(ha) && rval == QLA_COMMAND_ERROR &&
|
||||
if ((IS_QLA28XX(ha) || IS_QLA29XX(ha)) && rval == QLA_COMMAND_ERROR &&
|
||||
mcp->mb[1] == 0x27 && retry) {
|
||||
semaphore = 1;
|
||||
retry--;
|
||||
@@ -793,17 +800,20 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x119a,
|
||||
"fw_ability_mask=%x.\n", ha->fw_ability_mask);
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1027, "exchanges=%x.\n", mcp->mb[1]);
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
ha->max_supported_speed = mcp->mb[2] & (BIT_0|BIT_1);
|
||||
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
ha->max_supported_speed = mcp->mb[2] & (BIT_0|BIT_1|BIT_2|BIT_3);
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x119b, "max_supported_speed=%s.\n",
|
||||
ha->max_supported_speed == 0 ? "16Gps" :
|
||||
ha->max_supported_speed == 1 ? "32Gps" :
|
||||
ha->max_supported_speed == 2 ? "64Gps" : "unknown");
|
||||
ha->max_supported_speed == 2 ? "64Gps" :
|
||||
ha->max_supported_speed == 3 ? "128Gps" : "unknown");
|
||||
if (vha->min_supported_speed) {
|
||||
ha->min_supported_speed = mcp->mb[5] &
|
||||
(BIT_0 | BIT_1 | BIT_2);
|
||||
(BIT_0 | BIT_1 | BIT_2 | BIT_3);
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x119c,
|
||||
"min_supported_speed=%s.\n",
|
||||
ha->min_supported_speed == 7 ? "128Gps" :
|
||||
ha->min_supported_speed == 6 ? "64Gps" :
|
||||
ha->min_supported_speed == 5 ? "32Gps" :
|
||||
ha->min_supported_speed == 4 ? "16Gps" :
|
||||
@@ -812,7 +822,7 @@ qla2x00_execute_fw(scsi_qla_host_t *vha, uint32_t risc_addr)
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_QLA28XX(ha) && (mcp->mb[5] & EDIF_HW_SUPPORT)) {
|
||||
if ((IS_QLA28XX(ha) || IS_QLA29XX(ha)) && (mcp->mb[5] & EDIF_HW_SUPPORT)) {
|
||||
ha->flags.edif_hw = 1;
|
||||
ql_log(ql_log_info, vha, 0xffff,
|
||||
"%s: edif HW\n", __func__);
|
||||
@@ -846,15 +856,19 @@ qla28xx_load_flash_firmware(scsi_qla_host_t *vha)
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA28XX(ha))
|
||||
if (!IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
return rval;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x11a6,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
mcp->mb[0] = MBC_LOAD_FLASH_FIRMWARE;
|
||||
mcp->mb[1] = 0;
|
||||
mcp->out_mb = MBX_2 | MBX_1 | MBX_0;
|
||||
mcp->in_mb = MBX_0;
|
||||
if (IS_QLA29XX(ha))
|
||||
mcp->in_mb = MBX_1 | MBX_0;
|
||||
else
|
||||
mcp->in_mb = MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
@@ -1125,7 +1139,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
|
||||
mcp->in_mb |= MBX_13|MBX_12|MBX_11|MBX_10|MBX_9|MBX_8;
|
||||
if (IS_FWI2_CAPABLE(ha))
|
||||
mcp->in_mb |= MBX_17|MBX_16|MBX_15;
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
mcp->in_mb |=
|
||||
MBX_25|MBX_24|MBX_23|MBX_22|MBX_21|MBX_20|MBX_19|MBX_18|
|
||||
MBX_14|MBX_13|MBX_11|MBX_10|MBX_9|MBX_8|MBX_7;
|
||||
@@ -1201,7 +1215,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
|
||||
vha->flags.nvme2_enabled = 1;
|
||||
}
|
||||
|
||||
if (IS_QLA28XX(ha) && ha->flags.edif_hw && ql2xsecenable &&
|
||||
if ((IS_QLA28XX(ha) || IS_QLA29XX(ha)) && ha->flags.edif_hw && ql2xsecenable &&
|
||||
(ha->fw_attributes_ext[0] & FW_ATTR_EXT0_EDIF)) {
|
||||
ha->flags.edif_enabled = 1;
|
||||
ql_log(ql_log_info, vha, 0xffff,
|
||||
@@ -1209,7 +1223,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
|
||||
}
|
||||
}
|
||||
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
ha->serdes_version[0] = mcp->mb[7] & 0xff;
|
||||
ha->serdes_version[1] = mcp->mb[8] >> 8;
|
||||
ha->serdes_version[2] = mcp->mb[8] & 0xff;
|
||||
@@ -1223,7 +1237,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha)
|
||||
ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20];
|
||||
ha->fw_ddr_ram_start = (mcp->mb[23] << 16) | mcp->mb[22];
|
||||
ha->fw_ddr_ram_end = (mcp->mb[25] << 16) | mcp->mb[24];
|
||||
if (IS_QLA28XX(ha)) {
|
||||
if (IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
if (mcp->mb[16] & BIT_10)
|
||||
ha->flags.secure_fw = 1;
|
||||
|
||||
@@ -1758,7 +1772,7 @@ 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) || IS_QLA29XX(vha->hw))
|
||||
mcp->in_mb |= MBX_15|MBX_21|MBX_22|MBX_23;
|
||||
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
@@ -1813,7 +1827,7 @@ 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) || IS_QLA29XX(vha->hw)) {
|
||||
vha->bbcr = mcp->mb[15];
|
||||
if (mcp->mb[7] & SCM_EDC_ACC_RECEIVED) {
|
||||
ql_log(ql_log_info, vha, 0x11a4,
|
||||
@@ -1954,7 +1968,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
|
||||
|
||||
/* 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))
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
/* mb3 is additional info about the installed SFP. */
|
||||
mcp->in_mb |= MBX_3;
|
||||
mcp->buf_size = size;
|
||||
@@ -1978,7 +1992,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size)
|
||||
0x0104d, ha->ex_init_cb, sizeof(*ha->ex_init_cb));
|
||||
}
|
||||
} else {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
if (mcp->mb[2] == 6 || mcp->mb[3] == 2)
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x119d,
|
||||
"Invalid SFP/Validation Failed\n");
|
||||
@@ -2269,7 +2283,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
|
||||
else
|
||||
mcp->in_mb = MBX_1|MBX_0;
|
||||
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
mcp->mb[12] = 0;
|
||||
mcp->out_mb |= MBX_12;
|
||||
mcp->in_mb |= MBX_12;
|
||||
@@ -2287,7 +2301,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
|
||||
states[3] = mcp->mb[4];
|
||||
states[4] = mcp->mb[5];
|
||||
states[5] = mcp->mb[6]; /* DPORT status */
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
states[11] = mcp->mb[12]; /* MPI state. */
|
||||
}
|
||||
|
||||
@@ -2295,7 +2309,7 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
|
||||
/*EMPTY*/
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1055, "Failed=%x.\n", rval);
|
||||
} else {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
if (mcp->mb[2] == 6 || mcp->mb[3] == 2)
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x119e,
|
||||
"Invalid SFP/Validation Failed\n");
|
||||
@@ -2559,7 +2573,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
|
||||
uint8_t area, uint8_t al_pa, uint16_t *mb, uint8_t opt)
|
||||
{
|
||||
int rval;
|
||||
|
||||
void *lg_buf;
|
||||
struct logio_entry_24xx *lg;
|
||||
dma_addr_t lg_dma;
|
||||
uint32_t iop[2];
|
||||
@@ -2574,12 +2588,13 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
|
||||
else
|
||||
req = ha->req_q_map[0];
|
||||
|
||||
lg = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
|
||||
if (lg == NULL) {
|
||||
lg_buf = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
|
||||
if (!lg_buf) {
|
||||
ql_log(ql_log_warn, vha, 0x1062,
|
||||
"Failed to allocate login IOCB.\n");
|
||||
return QLA_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
lg = lg_buf;
|
||||
|
||||
lg->entry_type = LOGINOUT_PORT_IOCB_TYPE;
|
||||
lg->entry_count = 1;
|
||||
@@ -2593,8 +2608,9 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
|
||||
lg->port_id[0] = al_pa;
|
||||
lg->port_id[1] = area;
|
||||
lg->port_id[2] = domain;
|
||||
lg->vp_index = vha->vp_idx;
|
||||
rval = qla2x00_issue_iocb_timeout(vha, lg, lg_dma, 0,
|
||||
qla_logio_set_vp_index(ha, lg, vha->vp_idx);
|
||||
|
||||
rval = qla2x00_issue_iocb_timeout(vha, lg_buf, lg_dma, 0,
|
||||
(ha->r_a_tov / 10 * 2) + 2);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1063,
|
||||
@@ -2664,7 +2680,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
|
||||
*/
|
||||
}
|
||||
|
||||
dma_pool_free(ha->s_dma_pool, lg, lg_dma);
|
||||
dma_pool_free(ha->s_dma_pool, lg_buf, lg_dma);
|
||||
|
||||
return rval;
|
||||
}
|
||||
@@ -2835,6 +2851,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
|
||||
uint8_t area, uint8_t al_pa)
|
||||
{
|
||||
int rval;
|
||||
void *lg_buf;
|
||||
struct logio_entry_24xx *lg;
|
||||
dma_addr_t lg_dma;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
@@ -2843,12 +2860,13 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x106d,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
lg = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
|
||||
if (lg == NULL) {
|
||||
lg_buf = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma);
|
||||
if (!lg_buf) {
|
||||
ql_log(ql_log_warn, vha, 0x106e,
|
||||
"Failed to allocate logout IOCB.\n");
|
||||
return QLA_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
lg = lg_buf;
|
||||
|
||||
req = vha->req;
|
||||
lg->entry_type = LOGINOUT_PORT_IOCB_TYPE;
|
||||
@@ -2861,8 +2879,9 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
|
||||
lg->port_id[0] = al_pa;
|
||||
lg->port_id[1] = area;
|
||||
lg->port_id[2] = domain;
|
||||
lg->vp_index = vha->vp_idx;
|
||||
rval = qla2x00_issue_iocb_timeout(vha, lg, lg_dma, 0,
|
||||
qla_logio_set_vp_index(ha, lg, vha->vp_idx);
|
||||
|
||||
rval = qla2x00_issue_iocb_timeout(vha, lg_buf, lg_dma, 0,
|
||||
(ha->r_a_tov / 10 * 2) + 2);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x106f,
|
||||
@@ -2884,7 +2903,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain,
|
||||
"Done %s.\n", __func__);
|
||||
}
|
||||
|
||||
dma_pool_free(ha->s_dma_pool, lg, lg_dma);
|
||||
dma_pool_free(ha->s_dma_pool, lg_buf, lg_dma);
|
||||
|
||||
return rval;
|
||||
}
|
||||
@@ -3079,7 +3098,8 @@ qla2x00_get_resource_cnts(scsi_qla_host_t *vha)
|
||||
mcp->out_mb = MBX_0;
|
||||
mcp->in_mb = MBX_11|MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
if (IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha))
|
||||
mcp->in_mb |= MBX_12;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
@@ -3304,7 +3324,7 @@ qla24xx_abort_command(srb_t *sp)
|
||||
{
|
||||
int rval;
|
||||
unsigned long flags = 0;
|
||||
|
||||
void *abt_buf;
|
||||
struct abort_entry_24xx *abt;
|
||||
dma_addr_t abt_dma;
|
||||
uint32_t handle;
|
||||
@@ -3336,28 +3356,42 @@ qla24xx_abort_command(srb_t *sp)
|
||||
return QLA_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
abt = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &abt_dma);
|
||||
if (abt == NULL) {
|
||||
abt_buf = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &abt_dma);
|
||||
if (abt_buf == NULL) {
|
||||
ql_log(ql_log_warn, vha, 0x108d,
|
||||
"Failed to allocate abort IOCB.\n");
|
||||
return QLA_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
abt = abt_buf;
|
||||
|
||||
/*
|
||||
* abort_entry_24xx_ext overlays abort_entry_24xx through
|
||||
* req_que_no (offsets 0-17), and entry_status (offset 3) and
|
||||
* comp_status (offset 8) sit at identical offsets in both, so
|
||||
* the common header writes and the completion-status reads are
|
||||
* stride-agnostic and go through the 24xx view. Only port_id
|
||||
* (24xx-only) and vp_index width / offset diverge per stride.
|
||||
*/
|
||||
abt->entry_type = ABORT_IOCB_TYPE;
|
||||
abt->entry_count = 1;
|
||||
abt->handle = make_handle(req->id, abt->handle);
|
||||
abt->nport_handle = cpu_to_le16(fcport->loop_id);
|
||||
abt->handle_to_abort = make_handle(req->id, handle);
|
||||
abt->port_id[0] = fcport->d_id.b.al_pa;
|
||||
abt->port_id[1] = fcport->d_id.b.area;
|
||||
abt->port_id[2] = fcport->d_id.b.domain;
|
||||
abt->vp_index = fcport->vha->vp_idx;
|
||||
|
||||
abt->req_que_no = cpu_to_le16(req->id);
|
||||
/* Need to pass original sp */
|
||||
qla_nvme_abort_set_option(abt, sp);
|
||||
if (IS_QLA29XX(ha)) {
|
||||
((struct abort_entry_24xx_ext *)abt)->vp_index =
|
||||
cpu_to_le16(fcport->vha->vp_idx);
|
||||
} else {
|
||||
abt->port_id[0] = fcport->d_id.b.al_pa;
|
||||
abt->port_id[1] = fcport->d_id.b.area;
|
||||
abt->port_id[2] = fcport->d_id.b.domain;
|
||||
abt->vp_index = fcport->vha->vp_idx;
|
||||
}
|
||||
|
||||
rval = qla2x00_issue_iocb(vha, abt, abt_dma, 0);
|
||||
/* Need to pass original sp */
|
||||
qla_nvme_abort_set_option(abt_buf, sp);
|
||||
|
||||
rval = qla2x00_issue_iocb(vha, abt_buf, abt_dma, 0);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x108e,
|
||||
"Failed to issue IOCB (%x).\n", rval);
|
||||
@@ -3366,11 +3400,11 @@ qla24xx_abort_command(srb_t *sp)
|
||||
"Failed to complete IOCB -- error status (%x).\n",
|
||||
abt->entry_status);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
} else if (abt->nport_handle != cpu_to_le16(0)) {
|
||||
} else if (abt->comp_status != cpu_to_le16(0)) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1090,
|
||||
"Failed to complete IOCB -- completion status (%x).\n",
|
||||
le16_to_cpu(abt->nport_handle));
|
||||
if (abt->nport_handle == cpu_to_le16(CS_IOCB_ERROR))
|
||||
le16_to_cpu(abt->comp_status));
|
||||
if (abt->comp_status == cpu_to_le16(CS_IOCB_ERROR))
|
||||
rval = QLA_FUNCTION_PARAMETER_ERROR;
|
||||
else
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
@@ -3378,12 +3412,13 @@ qla24xx_abort_command(srb_t *sp)
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1091,
|
||||
"Done %s.\n", __func__);
|
||||
}
|
||||
|
||||
if (rval == QLA_SUCCESS)
|
||||
qla_nvme_abort_process_comp_status(abt, sp);
|
||||
qla_nvme_abort_process_comp_status(abt_buf, sp);
|
||||
|
||||
qla_wait_nvme_release_cmd_kref(sp);
|
||||
|
||||
dma_pool_free(ha->s_dma_pool, abt, abt_dma);
|
||||
dma_pool_free(ha->s_dma_pool, abt_buf, abt_dma);
|
||||
|
||||
return rval;
|
||||
}
|
||||
@@ -3391,7 +3426,9 @@ qla24xx_abort_command(srb_t *sp)
|
||||
struct tsk_mgmt_cmd {
|
||||
union {
|
||||
struct tsk_mgmt_entry tsk;
|
||||
struct tsk_mgmt_entry_ext tsk_ext;
|
||||
struct sts_entry_24xx sts;
|
||||
struct sts_entry_24xx_ext sts_ext;
|
||||
} p;
|
||||
};
|
||||
|
||||
@@ -3402,6 +3439,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
|
||||
int rval, rval2;
|
||||
struct tsk_mgmt_cmd *tsk;
|
||||
struct sts_entry_24xx *sts;
|
||||
struct qla_sts_fwi2 sf;
|
||||
dma_addr_t tsk_dma;
|
||||
scsi_qla_host_t *vha;
|
||||
struct qla_hw_data *ha;
|
||||
@@ -3428,16 +3466,25 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
|
||||
return QLA_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* tsk_mgmt_entry_ext overlays tsk_mgmt_entry through control_flags;
|
||||
* the common-header writes go through tsk->p.tsk and only port_id
|
||||
* (24xx-only) and vp_index width / offset diverge.
|
||||
*/
|
||||
tsk->p.tsk.entry_type = TSK_MGMT_IOCB_TYPE;
|
||||
tsk->p.tsk.entry_count = 1;
|
||||
tsk->p.tsk.handle = make_handle(req->id, tsk->p.tsk.handle);
|
||||
tsk->p.tsk.nport_handle = cpu_to_le16(fcport->loop_id);
|
||||
tsk->p.tsk.timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
|
||||
tsk->p.tsk.control_flags = cpu_to_le32(type);
|
||||
tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
|
||||
tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
|
||||
tsk->p.tsk.port_id[2] = fcport->d_id.b.domain;
|
||||
tsk->p.tsk.vp_index = fcport->vha->vp_idx;
|
||||
if (IS_QLA29XX(ha)) {
|
||||
tsk->p.tsk_ext.vp_index = cpu_to_le16(fcport->vha->vp_idx);
|
||||
} else {
|
||||
tsk->p.tsk.port_id[0] = fcport->d_id.b.al_pa;
|
||||
tsk->p.tsk.port_id[1] = fcport->d_id.b.area;
|
||||
tsk->p.tsk.port_id[2] = fcport->d_id.b.domain;
|
||||
tsk->p.tsk.vp_index = fcport->vha->vp_idx;
|
||||
}
|
||||
if (type == TCF_LUN_RESET) {
|
||||
int_to_scsilun(l, &tsk->p.tsk.lun);
|
||||
host_to_fcp_swap((uint8_t *)&tsk->p.tsk.lun,
|
||||
@@ -3459,18 +3506,20 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
|
||||
"Failed to complete IOCB -- completion status (%x).\n",
|
||||
le16_to_cpu(sts->comp_status));
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
} else if (le16_to_cpu(sts->scsi_status) &
|
||||
SS_RESPONSE_INFO_LEN_VALID) {
|
||||
if (le32_to_cpu(sts->rsp_data_len) < 4) {
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1097,
|
||||
"Ignoring inconsistent data length -- not enough "
|
||||
"response info (%d).\n",
|
||||
le32_to_cpu(sts->rsp_data_len));
|
||||
} else if (sts->data[3]) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1098,
|
||||
"Failed to complete IOCB -- response (%x).\n",
|
||||
sts->data[3]);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
} else {
|
||||
qla_sts_fwi2_extract(ha, sts, &sf);
|
||||
if (sf.scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
|
||||
if (sf.rsp_data_len < 4) {
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha,
|
||||
0x1097,
|
||||
"Ignoring inconsistent data length -- not enough response info (%d).\n",
|
||||
sf.rsp_data_len);
|
||||
} else if (sf.data[3]) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1098,
|
||||
"Failed to complete IOCB -- response (%x).\n",
|
||||
sf.data[3]);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3551,7 +3600,8 @@ qla2x00_write_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t data)
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) &&
|
||||
!IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
|
||||
!IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw) &&
|
||||
!IS_QLA29XX(vha->hw))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1182,
|
||||
@@ -3590,7 +3640,8 @@ qla2x00_read_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t *data)
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
|
||||
if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) &&
|
||||
!IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw))
|
||||
!IS_QLA27XX(vha->hw) && !IS_QLA28XX(vha->hw) &&
|
||||
!IS_QLA29XX(vha->hw))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1185,
|
||||
@@ -3860,7 +3911,7 @@ qla2x00_enable_fce_trace(scsi_qla_host_t *vha, dma_addr_t fce_dma,
|
||||
|
||||
if (!IS_QLA25XX(vha->hw) && !IS_QLA81XX(vha->hw) &&
|
||||
!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
|
||||
!IS_QLA28XX(vha->hw))
|
||||
!IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
if (unlikely(pci_channel_offline(vha->hw->pdev)))
|
||||
@@ -4035,15 +4086,18 @@ qla2x00_set_idma_speed(scsi_qla_host_t *vha, uint16_t loop_id,
|
||||
}
|
||||
|
||||
void
|
||||
qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
|
||||
struct vp_rpt_id_entry_24xx *rptid_entry)
|
||||
qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct vp_rpt_id_entry_24xx *rptid_entry = pkt;
|
||||
struct vp_rpt_id_entry_24xx_ext *rptid_entry_ext = pkt;
|
||||
scsi_qla_host_t *vp = NULL;
|
||||
unsigned long flags;
|
||||
int found;
|
||||
port_id_t id;
|
||||
struct fc_port *fcport;
|
||||
u16 vp_idx;
|
||||
u8 vp_status;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10b6,
|
||||
"Entered %s.\n", __func__);
|
||||
@@ -4051,6 +4105,16 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
|
||||
if (rptid_entry->entry_status != 0)
|
||||
return;
|
||||
|
||||
if (IS_QLA29XX(ha)) {
|
||||
vp_idx = le16_to_cpu(rptid_entry_ext->vp_idx_status) &
|
||||
EXT_VP_STATUS_VP_INDEX_MASK;
|
||||
vp_status = (le16_to_cpu(rptid_entry_ext->vp_idx_status) >>
|
||||
EXT_VP_STATUS_VP_STATUS_SHIFT) & 0x7f;
|
||||
} else {
|
||||
vp_idx = rptid_entry->vp_idx;
|
||||
vp_status = rptid_entry->vp_status;
|
||||
}
|
||||
|
||||
id.b.domain = rptid_entry->port_id[2];
|
||||
id.b.area = rptid_entry->port_id[1];
|
||||
id.b.al_pa = rptid_entry->port_id[0];
|
||||
@@ -4073,9 +4137,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
|
||||
} else if (rptid_entry->format == 1) {
|
||||
/* fabric */
|
||||
ql_dbg(ql_dbg_async, vha, 0x10b9,
|
||||
"Format 1: VP[%d] enabled - status %d - with "
|
||||
"port id %02x%02x%02x.\n", rptid_entry->vp_idx,
|
||||
rptid_entry->vp_status,
|
||||
"Format 1: VP[%d] enabled - status %d - with port id %02x%02x%02x.\n",
|
||||
vp_idx, vp_status,
|
||||
rptid_entry->port_id[2], rptid_entry->port_id[1],
|
||||
rptid_entry->port_id[0]);
|
||||
ql_dbg(ql_dbg_async, vha, 0x5075,
|
||||
@@ -4170,10 +4233,11 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
|
||||
ha->flags.gpsc_supported = 1;
|
||||
ha->current_topology = ISP_CFG_F;
|
||||
/* buffer to buffer credit flag */
|
||||
vha->flags.bbcr_enable = (rptid_entry->u.f1.bbcr & 0xf) != 0;
|
||||
vha->flags.bbcr_enable =
|
||||
(le16_to_cpu(rptid_entry->u.f1.bbcr) & 0xf) != 0;
|
||||
|
||||
if (rptid_entry->vp_idx == 0) {
|
||||
if (rptid_entry->vp_status == VP_STAT_COMPL) {
|
||||
if (vp_idx == 0) {
|
||||
if (vp_status == VP_STAT_COMPL) {
|
||||
/* FA-WWN is only for physical port */
|
||||
if (qla_ini_mode_enabled(vha) &&
|
||||
ha->flags.fawwpn_enabled &&
|
||||
@@ -4190,19 +4254,20 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
|
||||
set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
|
||||
set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
|
||||
} else {
|
||||
if (rptid_entry->vp_status != VP_STAT_COMPL &&
|
||||
rptid_entry->vp_status != VP_STAT_ID_CHG) {
|
||||
if (vp_status != VP_STAT_COMPL &&
|
||||
vp_status != VP_STAT_ID_CHG) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x10ba,
|
||||
"Could not acquire ID for VP[%d].\n",
|
||||
rptid_entry->vp_idx);
|
||||
vp_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
found = 0;
|
||||
spin_lock_irqsave(&ha->vport_slock, flags);
|
||||
list_for_each_entry(vp, &ha->vp_list, list) {
|
||||
if (rptid_entry->vp_idx == vp->vp_idx) {
|
||||
if (vp_idx == vp->vp_idx) {
|
||||
found = 1;
|
||||
atomic_inc(&vp->vref_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4220,6 +4285,8 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
|
||||
set_bit(VP_IDX_ACQUIRED, &vp->vp_flags);
|
||||
set_bit(REGISTER_FC4_NEEDED, &vp->dpc_flags);
|
||||
set_bit(REGISTER_FDMI_NEEDED, &vp->dpc_flags);
|
||||
|
||||
atomic_dec(&vp->vref_count);
|
||||
}
|
||||
set_bit(VP_DPC_NEEDED, &vha->dpc_flags);
|
||||
qla2xxx_wake_dpc(vha);
|
||||
@@ -4313,6 +4380,13 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
|
||||
return QLA_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
/*
|
||||
* vp_config_entry_24xx_ext overlays vp_config_entry_24xx for the
|
||||
* full 64-byte 24xx layout (the ext variant merely appends fields
|
||||
* at offset 64+ which this helper never touches), so the IOCB is
|
||||
* built and inspected through a single struct vp_config_entry_24xx
|
||||
* pointer regardless of adapter stride.
|
||||
*/
|
||||
vpmod->entry_type = VP_CONFIG_IOCB_TYPE;
|
||||
vpmod->entry_count = 1;
|
||||
vpmod->command = VCT_COMMAND_MOD_ENABLE_VPS;
|
||||
@@ -4330,10 +4404,10 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x10bd,
|
||||
"Failed to issue VP config IOCB (%x).\n", rval);
|
||||
} else if (vpmod->comp_status != 0) {
|
||||
} else if (vpmod->entry_status != 0) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x10be,
|
||||
"Failed to complete IOCB -- error status (%x).\n",
|
||||
vpmod->comp_status);
|
||||
vpmod->entry_status);
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
} else if (vpmod->comp_status != cpu_to_le16(CS_COMPLETE)) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x10bf,
|
||||
@@ -4341,7 +4415,6 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha)
|
||||
le16_to_cpu(vpmod->comp_status));
|
||||
rval = QLA_FUNCTION_FAILED;
|
||||
} else {
|
||||
/* EMPTY */
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x10c0,
|
||||
"Done %s.\n", __func__);
|
||||
fc_vport_set_state(vha->fc_vport, FC_VPORT_INITIALIZING);
|
||||
@@ -4584,7 +4657,8 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
mcp->mb[12] = req->qos;
|
||||
mcp->mb[11] = req->vp_idx;
|
||||
mcp->mb[13] = req->rid;
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha))
|
||||
mcp->mb[15] = 0;
|
||||
|
||||
mcp->mb[4] = req->id;
|
||||
@@ -4599,9 +4673,10 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
mcp->tov = MBX_TOV_SECONDS * 2;
|
||||
|
||||
if (IS_QLA81XX(ha) || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha))
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
mcp->in_mb |= MBX_1;
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha)) {
|
||||
mcp->out_mb |= MBX_15;
|
||||
/* debug q create issue in SR-IOV */
|
||||
mcp->in_mb |= MBX_9 | MBX_8 | MBX_7;
|
||||
@@ -4610,7 +4685,8 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
if (!(req->options & BIT_0)) {
|
||||
wrt_reg_dword(req->req_q_in, 0);
|
||||
if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
|
||||
!IS_QLA29XX(ha))
|
||||
wrt_reg_dword(req->req_q_out, 0);
|
||||
}
|
||||
spin_unlock_irqrestore(&ha->hardware_lock, flags);
|
||||
@@ -4654,7 +4730,8 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
mcp->mb[5] = rsp->length;
|
||||
mcp->mb[14] = rsp->msix->entry;
|
||||
mcp->mb[13] = rsp->rid;
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha))
|
||||
mcp->mb[15] = 0;
|
||||
|
||||
mcp->mb[4] = rsp->id;
|
||||
@@ -4671,7 +4748,8 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
if (IS_QLA81XX(ha)) {
|
||||
mcp->out_mb |= MBX_12|MBX_11|MBX_10;
|
||||
mcp->in_mb |= MBX_1;
|
||||
} else if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
} else if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha)) {
|
||||
mcp->out_mb |= MBX_15|MBX_12|MBX_11|MBX_10;
|
||||
mcp->in_mb |= MBX_1;
|
||||
/* debug q create issue in SR-IOV */
|
||||
@@ -4681,7 +4759,8 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
spin_lock_irqsave(&ha->hardware_lock, flags);
|
||||
if (!(rsp->options & BIT_0)) {
|
||||
wrt_reg_dword(rsp->rsp_q_out, 0);
|
||||
if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
|
||||
!IS_QLA29XX(ha))
|
||||
wrt_reg_dword(rsp->rsp_q_in, 0);
|
||||
}
|
||||
|
||||
@@ -5064,7 +5143,8 @@ qla25xx_set_els_cmds_supported(scsi_qla_host_t *vha)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA25XX(ha) && !IS_QLA2031(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
|
||||
!IS_QLA29XX(ha))
|
||||
return QLA_SUCCESS;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1197,
|
||||
@@ -5469,10 +5549,10 @@ qla2x00_echo_test(scsi_qla_host_t *vha, struct msg_echo_lb *mreq,
|
||||
|
||||
mcp->in_mb = MBX_0;
|
||||
if (IS_CNA_CAPABLE(ha) || IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha) ||
|
||||
IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
mcp->in_mb |= MBX_1;
|
||||
if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha))
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
mcp->in_mb |= MBX_3;
|
||||
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
@@ -5643,6 +5723,8 @@ qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode)
|
||||
case PORT_SPEED_8GB:
|
||||
case PORT_SPEED_16GB:
|
||||
case PORT_SPEED_32GB:
|
||||
case PORT_SPEED_64GB:
|
||||
case PORT_SPEED_128GB:
|
||||
val = ha->set_data_rate;
|
||||
break;
|
||||
default:
|
||||
@@ -5659,7 +5741,7 @@ qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode)
|
||||
|
||||
mcp->out_mb = MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_2|MBX_1|MBX_0;
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
mcp->in_mb |= MBX_4|MBX_3;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
@@ -5697,7 +5779,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
|
||||
mcp->mb[1] = QLA_GET_DATA_RATE;
|
||||
mcp->out_mb = MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_2|MBX_1|MBX_0;
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
mcp->in_mb |= MBX_4|MBX_3;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
@@ -5706,10 +5788,11 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x1107,
|
||||
"Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]);
|
||||
} else {
|
||||
if (mcp->mb[1] != 0x7)
|
||||
if (mcp->mb[1] != 0x7 || IS_QLA28XX(ha) || IS_QLA29XX(ha))
|
||||
ha->link_data_rate = mcp->mb[1];
|
||||
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha)) {
|
||||
if (mcp->mb[4] & BIT_0)
|
||||
ql_log(ql_log_info, vha, 0x11a2,
|
||||
"FEC=enabled (data rate).\n");
|
||||
@@ -5717,8 +5800,6 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha)
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108,
|
||||
"Done %s.\n", __func__);
|
||||
if (mcp->mb[1] != 0x7)
|
||||
ha->link_data_rate = mcp->mb[1];
|
||||
}
|
||||
|
||||
return rval;
|
||||
@@ -6492,7 +6573,7 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha,
|
||||
dma_addr_t dd_dma;
|
||||
|
||||
if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
|
||||
!IS_QLA28XX(vha->hw))
|
||||
!IS_QLA28XX(vha->hw) && !IS_QLA29XX(vha->hw))
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x119f,
|
||||
@@ -7254,3 +7335,192 @@ int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, uint16_t *state)
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int qla29xx_flash_block_read(scsi_qla_host_t *vha, dma_addr_t req_dma,
|
||||
uint32_t flash_addr, uint32_t flash_size,
|
||||
uint16_t reg_code, uint16_t opt)
|
||||
{
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int rval = 0;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1067,
|
||||
"Entered %s options 0x%x.\n", __func__, opt);
|
||||
|
||||
memset(mcp->mb, 0, sizeof(mcp->mb));
|
||||
|
||||
if (!is_flash_read(opt)) {
|
||||
ql_log(ql_log_info, vha, 0x1068,
|
||||
"%s: Invalid flash option 0x%x.\n", __func__, opt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mcp->mb[0] = MBC_RD_WR_FLASH;
|
||||
|
||||
/* mailbox option field :
|
||||
* TIM img or Img : BIT_15 (1/0)
|
||||
* Last seg img : BIT_11 (1)
|
||||
* First seg img : BIT_10 (1)
|
||||
* dword or block : BIT_9 (1/0)
|
||||
* flash MBR update : BIT_8 (1/0)
|
||||
* Secure or non-secure : BIT_7 (1/0)
|
||||
* Write or Read : BIT_6 (1/0)
|
||||
* Last block img : BIT_5 (1)
|
||||
* First block img : BIT_4 (1)
|
||||
* Request type : (BIT3 - BIT_0)
|
||||
* - Normal
|
||||
* - Normal, Force Sema
|
||||
* - Initialize
|
||||
* - Initialize, Force sema
|
||||
* - Abort secured update
|
||||
*/
|
||||
mcp->mb[1] = opt;
|
||||
mcp->mb[2] = reg_code;
|
||||
|
||||
mcp->mb[3] = MSW(flash_size);
|
||||
mcp->mb[4] = LSW(flash_size);
|
||||
|
||||
mcp->mb[5] = MSW(req_dma);
|
||||
mcp->mb[6] = LSW(req_dma);
|
||||
mcp->mb[7] = MSW(MSD(req_dma));
|
||||
mcp->mb[8] = LSW(MSD(req_dma));
|
||||
|
||||
mcp->mb[9] = MSW(flash_addr);
|
||||
mcp->mb[10] = LSW(flash_addr);
|
||||
|
||||
mcp->out_mb =
|
||||
MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x103f,
|
||||
"Failed=%x mb=(0x%x,0x%x,0x%x,0x%x).\n",
|
||||
rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1043,
|
||||
"Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
|
||||
mcp->mb[0], mcp->mb[1], mcp->mb[2]);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int qla29xx_flash_block_write(scsi_qla_host_t *vha, dma_addr_t req_dma,
|
||||
uint32_t flash_addr, uint32_t flash_size,
|
||||
uint16_t reg_code, uint16_t opt)
|
||||
{
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int rval = 0;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1069,
|
||||
"Entered %s options 0x%x.\n", __func__, opt);
|
||||
|
||||
memset(mcp->mb, 0, sizeof(mcp->mb));
|
||||
|
||||
if (!is_flash_write(opt)) {
|
||||
ql_log(ql_log_info, vha, 0x106a,
|
||||
"%s: Invalid flash option 0x%x.\n", __func__, opt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mcp->mb[0] = MBC_RD_WR_FLASH;
|
||||
|
||||
/* mailbox option field :
|
||||
* TIM img or Img : BIT_15 (1/0)
|
||||
* Last seg img : BIT_11 (1)
|
||||
* First seg img : BIT_10 (1)
|
||||
* dword or block : BIT_9 (1/0)
|
||||
* flash MBR update : BIT_8 (1/0)
|
||||
* Secure or non-secure : BIT_7 (1/0)
|
||||
* Write or Read : BIT_6 (1/0)
|
||||
* Last block img : BIT_5 (1)
|
||||
* First block img : BIT_4 (1)
|
||||
* Request type : (BIT3 - BIT_0)
|
||||
* - Normal
|
||||
* - Normal, Force Sema
|
||||
* - Initialize
|
||||
* - Initialize, Force sema
|
||||
* - Abort secured update
|
||||
*/
|
||||
mcp->mb[1] = opt;
|
||||
mcp->mb[2] = reg_code;
|
||||
|
||||
mcp->mb[3] = MSW(flash_size);
|
||||
mcp->mb[4] = LSW(flash_size);
|
||||
|
||||
mcp->mb[5] = MSW(req_dma);
|
||||
mcp->mb[6] = LSW(req_dma);
|
||||
mcp->mb[7] = MSW(MSD(req_dma));
|
||||
mcp->mb[8] = LSW(MSD(req_dma));
|
||||
|
||||
mcp->mb[9] = MSW(flash_addr);
|
||||
mcp->mb[10] = LSW(flash_addr);
|
||||
|
||||
mcp->out_mb =
|
||||
MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x110a,
|
||||
"Failed=%x mb=(0x%x,0x%x,0x%x,0x%x).\n",
|
||||
rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110b,
|
||||
"Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
|
||||
mcp->mb[0], mcp->mb[1], mcp->mb[2]);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla29xx_load_dump_mpi(scsi_qla_host_t *vha, uint16_t opt, uint32_t mpi_addr,
|
||||
uint32_t dlen, dma_addr_t req_dma)
|
||||
{
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int rval = 0;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xffff,
|
||||
"Entered %s mpi_addr 0x%x len 0x%x opt 0x%x.\n",
|
||||
__func__, mpi_addr, dlen, opt);
|
||||
|
||||
memset(mcp->mb, 0, sizeof(mcp->mb));
|
||||
|
||||
mcp->mb[0] = MBC_LOAD_DUMP_MPI_RAM;
|
||||
mcp->mb[9] = opt;
|
||||
mcp->mb[1] = LSW(mpi_addr);
|
||||
mcp->mb[8] = MSW(mpi_addr);
|
||||
|
||||
mcp->mb[2] = MSW(req_dma);
|
||||
mcp->mb[3] = LSW(req_dma);
|
||||
mcp->mb[6] = MSW(MSD(req_dma));
|
||||
mcp->mb[7] = LSW(MSD(req_dma));
|
||||
|
||||
mcp->mb[4] = MSW(dlen);
|
||||
mcp->mb[5] = LSW(dlen);
|
||||
|
||||
mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
if (rval != QLA_SUCCESS)
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x110a,
|
||||
"Failed=%x mb=(0x%x,0x%x).\n",
|
||||
rval, mcp->mb[0], mcp->mb[1]);
|
||||
else
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110b,
|
||||
"Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
|
||||
mcp->mb[0], mcp->mb[1], mcp->mb[2]);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
@@ -574,16 +574,19 @@ qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint16_t que_id = req->id;
|
||||
size_t req_entry_size = qla_req_entry_size(ha);
|
||||
|
||||
dma_free_coherent(&ha->pdev->dev, (req->length + 1) *
|
||||
sizeof(request_t), req->ring, req->dma);
|
||||
if (req->ring)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
(req->length + 1) * req_entry_size,
|
||||
req->ring, req->dma);
|
||||
req->ring = NULL;
|
||||
req->dma = 0;
|
||||
if (que_id) {
|
||||
mutex_lock(&ha->mq_lock);
|
||||
ha->req_q_map[que_id] = NULL;
|
||||
mutex_lock(&ha->vport_lock);
|
||||
clear_bit(que_id, ha->req_qid_map);
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
}
|
||||
kfree(req->outstanding_cmds);
|
||||
kfree(req);
|
||||
@@ -594,6 +597,7 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint16_t que_id = rsp->id;
|
||||
size_t rsp_entry_size = qla_rsp_entry_size(ha);
|
||||
|
||||
if (rsp->msix && rsp->msix->have_irq) {
|
||||
free_irq(rsp->msix->vector, rsp->msix->handle);
|
||||
@@ -601,15 +605,18 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
rsp->msix->in_use = 0;
|
||||
rsp->msix->handle = NULL;
|
||||
}
|
||||
dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) *
|
||||
sizeof(response_t), rsp->ring, rsp->dma);
|
||||
|
||||
if (rsp->ring)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
(rsp->length + 1) * rsp_entry_size,
|
||||
rsp->ring, rsp->dma);
|
||||
rsp->ring = NULL;
|
||||
rsp->dma = 0;
|
||||
if (que_id) {
|
||||
mutex_lock(&ha->mq_lock);
|
||||
ha->rsp_q_map[que_id] = NULL;
|
||||
mutex_lock(&ha->vport_lock);
|
||||
clear_bit(que_id, ha->rsp_qid_map);
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
}
|
||||
kfree(rsp);
|
||||
}
|
||||
@@ -706,6 +713,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
|
||||
uint16_t que_id = 0;
|
||||
device_reg_t *reg;
|
||||
uint32_t cnt;
|
||||
size_t req_entry_size = qla_req_entry_size(ha);
|
||||
|
||||
req = kzalloc_obj(struct req_que);
|
||||
if (req == NULL) {
|
||||
@@ -716,13 +724,17 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
|
||||
|
||||
req->length = REQUEST_ENTRY_CNT_24XX;
|
||||
req->ring = dma_alloc_coherent(&ha->pdev->dev,
|
||||
(req->length + 1) * sizeof(request_t),
|
||||
(req->length + 1) * req_entry_size,
|
||||
&req->dma, GFP_KERNEL);
|
||||
if (req->ring == NULL) {
|
||||
ql_log(ql_log_fatal, base_vha, 0x00da,
|
||||
"Failed to allocate memory for request_ring.\n");
|
||||
goto que_failed;
|
||||
}
|
||||
if (IS_QLA29XX(ha)) {
|
||||
req->ring_ext = (struct request_ext *)req->ring;
|
||||
req->ring_ext_ptr = req->ring_ext;
|
||||
}
|
||||
|
||||
ret = qla2x00_alloc_outstanding_cmds(ha, req);
|
||||
if (ret != QLA_SUCCESS)
|
||||
@@ -768,7 +780,15 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
|
||||
req->outstanding_cmds[cnt] = NULL;
|
||||
req->current_outstanding_cmd = 1;
|
||||
|
||||
/*
|
||||
* Re-anchor both the 24xx (ring_ptr) and 29xx (ring_ext_ptr) views
|
||||
* at the start of the ring. Keeping them reset together here
|
||||
* guarantees they stay in sync with ring_index=0 regardless of any
|
||||
* prior allocator/fast-path advances against this queue.
|
||||
*/
|
||||
req->ring_ptr = req->ring;
|
||||
if (IS_QLA29XX(ha))
|
||||
req->ring_ext_ptr = req->ring_ext;
|
||||
req->ring_index = 0;
|
||||
req->cnt = req->length;
|
||||
req->id = que_id;
|
||||
@@ -776,7 +796,15 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
|
||||
req->req_q_in = ®->isp25mq.req_q_in;
|
||||
req->req_q_out = ®->isp25mq.req_q_out;
|
||||
req->max_q_depth = ha->req_q_map[0]->max_q_depth;
|
||||
req->out_ptr = (uint16_t *)(req->ring + req->length);
|
||||
/*
|
||||
* out_ptr sits in the scratch slot immediately after the ring. Use
|
||||
* the 29xx-stride pointer when the ring is 128-byte-per-entry so the
|
||||
* pointer arithmetic resolves to the correct byte offset.
|
||||
*/
|
||||
if (IS_QLA29XX(ha))
|
||||
req->out_ptr = (uint16_t *)(req->ring_ext + req->length);
|
||||
else
|
||||
req->out_ptr = (uint16_t *)(req->ring + req->length);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
|
||||
"ring_ptr=%p ring_index=%d, "
|
||||
@@ -794,9 +822,6 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
|
||||
if (ret != QLA_SUCCESS) {
|
||||
ql_log(ql_log_fatal, base_vha, 0x00df,
|
||||
"%s failed.\n", __func__);
|
||||
mutex_lock(&ha->mq_lock);
|
||||
clear_bit(que_id, ha->req_qid_map);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
goto que_failed;
|
||||
}
|
||||
vha->flags.qpairs_req_created = 1;
|
||||
@@ -833,6 +858,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
|
||||
struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
|
||||
uint16_t que_id = 0;
|
||||
device_reg_t *reg;
|
||||
size_t rsp_entry_size = qla_rsp_entry_size(ha);
|
||||
|
||||
rsp = kzalloc_obj(struct rsp_que);
|
||||
if (rsp == NULL) {
|
||||
@@ -843,13 +869,17 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
|
||||
|
||||
rsp->length = RESPONSE_ENTRY_CNT_MQ;
|
||||
rsp->ring = dma_alloc_coherent(&ha->pdev->dev,
|
||||
(rsp->length + 1) * sizeof(response_t),
|
||||
(rsp->length + 1) * rsp_entry_size,
|
||||
&rsp->dma, GFP_KERNEL);
|
||||
if (rsp->ring == NULL) {
|
||||
ql_log(ql_log_warn, base_vha, 0x00e1,
|
||||
"Failed to allocate memory for response ring.\n");
|
||||
goto que_failed;
|
||||
}
|
||||
if (IS_QLA29XX(ha)) {
|
||||
rsp->ring_ext = (struct response_ext *)rsp->ring;
|
||||
rsp->ring_ext_ptr = rsp->ring_ext;
|
||||
}
|
||||
|
||||
mutex_lock(&ha->mq_lock);
|
||||
que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues);
|
||||
@@ -888,7 +918,10 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
|
||||
reg = ISP_QUE_REG(ha, que_id);
|
||||
rsp->rsp_q_in = ®->isp25mq.rsp_q_in;
|
||||
rsp->rsp_q_out = ®->isp25mq.rsp_q_out;
|
||||
rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
|
||||
if (IS_QLA29XX(ha))
|
||||
rsp->in_ptr = (uint16_t *)(rsp->ring_ext + rsp->length);
|
||||
else
|
||||
rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
ql_dbg(ql_dbg_multiq, base_vha, 0xc00b,
|
||||
"options=%x id=%d rsp_q_in=%p rsp_q_out=%p\n",
|
||||
@@ -908,9 +941,6 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
|
||||
if (ret != QLA_SUCCESS) {
|
||||
ql_log(ql_log_fatal, base_vha, 0x00e7,
|
||||
"%s failed.\n", __func__);
|
||||
mutex_lock(&ha->mq_lock);
|
||||
clear_bit(que_id, ha->rsp_qid_map);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
goto que_failed;
|
||||
}
|
||||
vha->flags.qpairs_rsp_created = 1;
|
||||
@@ -957,6 +987,14 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd)
|
||||
if (vp_index == 0 || vp_index >= ha->max_npiv_vports)
|
||||
return QLA_PARAMETER_ERROR;
|
||||
|
||||
/*
|
||||
* The VP_CTRL IOCB selects the target VP through a fixed 128-bit
|
||||
* (16-byte) vp_idx_map bitmap, so vp_index must fit within it even
|
||||
* if firmware advertises more NPIV vports.
|
||||
*/
|
||||
if (vp_index > sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8)
|
||||
return QLA_PARAMETER_ERROR;
|
||||
|
||||
/* ref: INIT */
|
||||
sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL);
|
||||
if (!sp)
|
||||
|
||||
@@ -374,6 +374,7 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
|
||||
srb_t *sp;
|
||||
int rval = QLA_FUNCTION_FAILED;
|
||||
uint8_t cnt = 0;
|
||||
unsigned long flags;
|
||||
|
||||
if (!fcport || fcport->deleted)
|
||||
goto out;
|
||||
@@ -440,7 +441,9 @@ static int qla_nvme_xmt_ls_rsp(struct nvme_fc_local_port *lport,
|
||||
a.vp_idx = vha->vp_idx;
|
||||
a.nport_handle = uctx->nport_handle;
|
||||
a.xchg_address = uctx->exchange_address;
|
||||
spin_lock_irqsave(ha->base_qpair->qp_lock_ptr, flags);
|
||||
qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true);
|
||||
spin_unlock_irqrestore(ha->base_qpair->qp_lock_ptr, flags);
|
||||
kfree(uctx);
|
||||
return rval;
|
||||
}
|
||||
@@ -463,7 +466,6 @@ static void qla_nvme_ls_abort(struct nvme_fc_local_port *lport,
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->cmd_lock, flags);
|
||||
|
||||
INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
|
||||
schedule_work(&priv->abort_work);
|
||||
}
|
||||
|
||||
@@ -501,6 +503,7 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
|
||||
priv->sp = sp;
|
||||
kref_init(&sp->cmd_kref);
|
||||
spin_lock_init(&priv->cmd_lock);
|
||||
INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
|
||||
nvme = &sp->u.iocb_cmd;
|
||||
priv->fd = fd;
|
||||
nvme->u.nvme.desc = fd;
|
||||
@@ -545,7 +548,6 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport,
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->cmd_lock, flags);
|
||||
|
||||
INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
|
||||
schedule_work(&priv->abort_work);
|
||||
}
|
||||
|
||||
@@ -554,7 +556,8 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
||||
unsigned long flags;
|
||||
uint32_t *clr_ptr;
|
||||
uint32_t handle;
|
||||
struct cmd_nvme *cmd_pkt;
|
||||
struct cmd_nvme *cmd_pkt = NULL;
|
||||
struct cmd_nvme_ext *cmd_pkt_ext = NULL;
|
||||
uint16_t cnt, i;
|
||||
uint16_t req_cnt;
|
||||
uint16_t tot_dsds;
|
||||
@@ -584,7 +587,10 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
||||
rval = -EBUSY;
|
||||
goto queuing_error;
|
||||
}
|
||||
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
|
||||
if (IS_QLA29XX(ha))
|
||||
req_cnt = qla29xx_calc_iocbs(vha, tot_dsds, NUM_NVME_DSDS);
|
||||
else
|
||||
req_cnt = qla24xx_calc_iocbs(vha, tot_dsds);
|
||||
|
||||
sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH;
|
||||
sp->iores.exch_cnt = 1;
|
||||
@@ -629,19 +635,62 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
||||
sp->handle = handle;
|
||||
req->cnt -= req_cnt;
|
||||
|
||||
cmd_pkt = (struct cmd_nvme *)req->ring_ptr;
|
||||
/*
|
||||
* 29xx operates on the 128-byte extended IOCB ring; the header
|
||||
* layout of struct cmd_nvme is identical to the head of struct
|
||||
* cmd_nvme_ext through 'byte_count', so the common-field writes
|
||||
* below go through cmd_pkt regardless of stride. Divergent tail
|
||||
* fields (port_id/vp_index, DSD array) are handled via
|
||||
* IS_QLA29XX(ha) branches.
|
||||
*
|
||||
* Enforce the layout contract at compile time so any future
|
||||
* change to either struct that breaks the common-header overlap
|
||||
* fails the build rather than silently corrupting IOCBs.
|
||||
*/
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, entry_type) !=
|
||||
offsetof(struct cmd_nvme_ext, entry_type));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, handle) !=
|
||||
offsetof(struct cmd_nvme_ext, handle));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, nport_handle) !=
|
||||
offsetof(struct cmd_nvme_ext, nport_handle));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, timeout) !=
|
||||
offsetof(struct cmd_nvme_ext, timeout));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, dseg_count) !=
|
||||
offsetof(struct cmd_nvme_ext, dseg_count));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, nvme_rsp_dsd_len) !=
|
||||
offsetof(struct cmd_nvme_ext, nvme_rsp_dsd_len));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, rsvd) !=
|
||||
offsetof(struct cmd_nvme_ext, rsvd));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, control_flags) !=
|
||||
offsetof(struct cmd_nvme_ext, control_flags));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, nvme_cmnd_dseg_len) !=
|
||||
offsetof(struct cmd_nvme_ext, nvme_cmnd_dseg_len));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, nvme_cmnd_dseg_address) !=
|
||||
offsetof(struct cmd_nvme_ext, nvme_cmnd_dseg_address));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, nvme_rsp_dseg_address) !=
|
||||
offsetof(struct cmd_nvme_ext, nvme_rsp_dseg_address));
|
||||
BUILD_BUG_ON(offsetof(struct cmd_nvme, byte_count) !=
|
||||
offsetof(struct cmd_nvme_ext, byte_count));
|
||||
BUILD_BUG_ON(sizeof_field(struct cmd_nvme, byte_count) !=
|
||||
sizeof_field(struct cmd_nvme_ext, byte_count));
|
||||
|
||||
if (IS_QLA29XX(ha))
|
||||
cmd_pkt = (struct cmd_nvme *)req->ring_ext_ptr;
|
||||
else
|
||||
cmd_pkt = (struct cmd_nvme *)req->ring_ptr;
|
||||
cmd_pkt_ext = (struct cmd_nvme_ext *)cmd_pkt;
|
||||
cmd_pkt->handle = make_handle(req->id, handle);
|
||||
|
||||
/* Zero out remaining portion of packet. */
|
||||
clr_ptr = (uint32_t *)cmd_pkt + 2;
|
||||
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
|
||||
if (IS_QLA29XX(ha))
|
||||
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE_EXT - 8);
|
||||
else
|
||||
memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
|
||||
|
||||
cmd_pkt->entry_status = 0;
|
||||
|
||||
/* Update entry type to indicate Command NVME IOCB */
|
||||
cmd_pkt->entry_type = COMMAND_NVME;
|
||||
|
||||
/* No data transfer how do we check buffer len == 0?? */
|
||||
if (fd->io_dir == NVMEFC_FCP_READ) {
|
||||
cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA);
|
||||
qpair->counters.input_bytes += fd->payload_length;
|
||||
@@ -666,18 +715,23 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
||||
if (sp->fcport->edif.enable && fd->io_dir != 0)
|
||||
cmd_pkt->control_flags |= cpu_to_le16(CF_EN_EDIF);
|
||||
|
||||
/* Set BIT_13 of control flags for Async event */
|
||||
if (vha->flags.nvme2_enabled &&
|
||||
cmd->sqe.common.opcode == nvme_admin_async_event) {
|
||||
cmd->sqe.common.opcode == nvme_admin_async_event)
|
||||
cmd_pkt->control_flags |= cpu_to_le16(CF_ADMIN_ASYNC_EVENT);
|
||||
}
|
||||
|
||||
/* Set NPORT-ID */
|
||||
cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id);
|
||||
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
|
||||
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
|
||||
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
|
||||
cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
|
||||
if (IS_QLA29XX(ha)) {
|
||||
/*
|
||||
* 29xx extended NVMe IOCB has no port_id[] field; vp_index is
|
||||
* a 9-bit __le16 (see CMD_EXT_VP_INDEX_MASK).
|
||||
*/
|
||||
cmd_pkt_ext->vp_index = cpu_to_le16(sp->fcport->vha->vp_idx);
|
||||
} else {
|
||||
cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa;
|
||||
cmd_pkt->port_id[1] = sp->fcport->d_id.b.area;
|
||||
cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain;
|
||||
cmd_pkt->vp_index = sp->fcport->vha->vp_idx;
|
||||
}
|
||||
|
||||
/* NVME RSP IU */
|
||||
cmd_pkt->nvme_rsp_dsd_len = cpu_to_le16(fd->rsplen);
|
||||
@@ -690,36 +744,51 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
||||
cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
|
||||
cmd_pkt->byte_count = cpu_to_le32(fd->payload_length);
|
||||
|
||||
/* One DSD is available in the Command Type NVME IOCB */
|
||||
avail_dsds = 1;
|
||||
cur_dsd = &cmd_pkt->nvme_dsd;
|
||||
/*
|
||||
* 24xx carries a single inline DSD in the NVMe command IOCB; 29xx
|
||||
* carries NUM_NVME_DSDS inline DSDs in the extended IOCB.
|
||||
*/
|
||||
if (IS_QLA29XX(ha)) {
|
||||
avail_dsds = NUM_NVME_DSDS;
|
||||
cur_dsd = &cmd_pkt_ext->nvme_dsd[0];
|
||||
} else {
|
||||
avail_dsds = 1;
|
||||
cur_dsd = &cmd_pkt->nvme_dsd;
|
||||
}
|
||||
sgl = fd->first_sgl;
|
||||
|
||||
/* Load data segments */
|
||||
for_each_sg(sgl, sg, tot_dsds, i) {
|
||||
cont_a64_entry_t *cont_pkt;
|
||||
|
||||
/* Allocate additional continuation packets? */
|
||||
if (avail_dsds == 0) {
|
||||
/*
|
||||
* Five DSDs are available in the Continuation
|
||||
* Type 1 IOCB.
|
||||
*/
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct cont_a64_entry_ext *cont_pkt;
|
||||
|
||||
/* Adjust ring index */
|
||||
req->ring_index++;
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ptr = req->ring;
|
||||
cont_pkt = qla2900_prep_cont_type1_iocb(vha,
|
||||
req);
|
||||
cur_dsd = cont_pkt->dsd;
|
||||
avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
|
||||
} else {
|
||||
req->ring_ptr++;
|
||||
}
|
||||
cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
|
||||
put_unaligned_le32(CONTINUE_A64_TYPE,
|
||||
&cont_pkt->entry_type);
|
||||
cont_a64_entry_t *cont_pkt;
|
||||
|
||||
cur_dsd = cont_pkt->dsd;
|
||||
avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
|
||||
/*
|
||||
* Five DSDs are available in the 24xx
|
||||
* Continuation Type 1 IOCB.
|
||||
*/
|
||||
req->ring_index++;
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ptr = req->ring;
|
||||
} else {
|
||||
req->ring_ptr++;
|
||||
}
|
||||
cont_pkt = (cont_a64_entry_t *)req->ring_ptr;
|
||||
put_unaligned_le32(CONTINUE_A64_TYPE,
|
||||
&cont_pkt->entry_type);
|
||||
|
||||
cur_dsd = cont_pkt->dsd;
|
||||
avail_dsds = ARRAY_SIZE(cont_pkt->dsd);
|
||||
}
|
||||
}
|
||||
|
||||
append_dsd64(&cur_dsd, sg);
|
||||
@@ -731,13 +800,7 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
||||
wmb();
|
||||
|
||||
/* Adjust ring index. */
|
||||
req->ring_index++;
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ptr = req->ring;
|
||||
} else {
|
||||
req->ring_ptr++;
|
||||
}
|
||||
qla_req_ring_advance(ha, req);
|
||||
|
||||
/* ignore nvme async cmd due to long timeout */
|
||||
if (!nvme->u.nvme.aen_op)
|
||||
@@ -746,7 +809,12 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
||||
/* Set chip new ring index. */
|
||||
wrt_reg_dword(req->req_q_in, req->ring_index);
|
||||
|
||||
if (vha->flags.process_response_queue &&
|
||||
/*
|
||||
* 29xx inline response drain would require the 128-byte response ring
|
||||
* view, which the 24xx qla24xx_process_response_queue() does not walk;
|
||||
* skip here and rely on the normal ISR path.
|
||||
*/
|
||||
if (!IS_QLA29XX(ha) && vha->flags.process_response_queue &&
|
||||
rsp->ring_ptr->signature != RESPONSE_PROCESSED)
|
||||
qla24xx_process_response_queue(vha, rsp);
|
||||
|
||||
@@ -811,6 +879,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport,
|
||||
|
||||
kref_init(&sp->cmd_kref);
|
||||
spin_lock_init(&priv->cmd_lock);
|
||||
INIT_WORK(&priv->abort_work, qla_nvme_abort_work);
|
||||
sp->priv = priv;
|
||||
priv->sp = sp;
|
||||
sp->type = SRB_NVME_CMD;
|
||||
@@ -1001,36 +1070,69 @@ int qla_nvme_register_hba(struct scsi_qla_host *vha)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qla_nvme_abort_set_option(struct abort_entry_24xx *abt, srb_t *orig_sp)
|
||||
void qla_nvme_abort_set_option(void *pkt, srb_t *orig_sp)
|
||||
{
|
||||
struct qla_hw_data *ha;
|
||||
struct abort_entry_24xx *abt = pkt;
|
||||
|
||||
if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
|
||||
return;
|
||||
|
||||
ha = orig_sp->fcport->vha->hw;
|
||||
|
||||
/*
|
||||
* abort_entry_24xx_ext overlays abort_entry_24xx through 'options'
|
||||
* (offset 10), so options writes are stride-agnostic. The drv
|
||||
* union sits at offset 56 in the 24xx layout but offset 24 in the
|
||||
* ext layout, so the drv writes need a typed pointer.
|
||||
*/
|
||||
WARN_ON_ONCE(abt->options & cpu_to_le16(BIT_0));
|
||||
/* Use Driver Specified Retry Count */
|
||||
abt->options |= cpu_to_le16(AOF_ABTS_RTY_CNT);
|
||||
abt->drv.abts_rty_cnt = cpu_to_le16(2);
|
||||
/* Use specified response timeout */
|
||||
abt->options |= cpu_to_le16(AOF_RSP_TIMEOUT);
|
||||
/* set it to 2 * r_a_tov in secs */
|
||||
abt->drv.rsp_timeout = cpu_to_le16(2 * (ha->r_a_tov / 10));
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct abort_entry_24xx_ext *abt_ext = pkt;
|
||||
|
||||
abt_ext->drv.abts_rty_cnt = cpu_to_le16(2);
|
||||
abt_ext->drv.rsp_timeout =
|
||||
cpu_to_le16(2 * (ha->r_a_tov / 10));
|
||||
} else {
|
||||
abt->drv.abts_rty_cnt = cpu_to_le16(2);
|
||||
abt->drv.rsp_timeout = cpu_to_le16(2 * (ha->r_a_tov / 10));
|
||||
}
|
||||
}
|
||||
|
||||
void qla_nvme_abort_process_comp_status(struct abort_entry_24xx *abt, srb_t *orig_sp)
|
||||
void qla_nvme_abort_process_comp_status(void *pkt, srb_t *orig_sp)
|
||||
{
|
||||
u16 comp_status;
|
||||
struct scsi_qla_host *vha;
|
||||
u8 rjt_vendor_unique, rjt_reason_expl, rjt_reason_code;
|
||||
struct abort_entry_24xx *abt = pkt;
|
||||
|
||||
if (!(ql2xabts_wait_nvme && QLA_ABTS_WAIT_ENABLED(orig_sp)))
|
||||
return;
|
||||
|
||||
vha = orig_sp->fcport->vha;
|
||||
|
||||
/*
|
||||
* comp_status sits at offset 8 in both layouts (the
|
||||
* nport_handle/comp_status union), so the read is
|
||||
* stride-agnostic. The fw union, like drv, lives at offset
|
||||
* 56 in the 24xx layout and offset 24 in the ext layout, so
|
||||
* those byte reads still need a typed pointer.
|
||||
*/
|
||||
comp_status = le16_to_cpu(abt->comp_status);
|
||||
if (IS_QLA29XX(vha->hw)) {
|
||||
struct abort_entry_24xx_ext *abt_ext = pkt;
|
||||
|
||||
rjt_vendor_unique = abt_ext->fw.ba_rjt_vendorUnique;
|
||||
rjt_reason_expl = abt_ext->fw.ba_rjt_reasonCodeExpl;
|
||||
rjt_reason_code = abt_ext->fw.ba_rjt_reasonCode;
|
||||
} else {
|
||||
rjt_vendor_unique = abt->fw.ba_rjt_vendorUnique;
|
||||
rjt_reason_expl = abt->fw.ba_rjt_reasonCodeExpl;
|
||||
rjt_reason_code = abt->fw.ba_rjt_reasonCode;
|
||||
}
|
||||
|
||||
switch (comp_status) {
|
||||
case CS_RESET: /* reset event aborted */
|
||||
case CS_ABORTED: /* IOCB was cleaned */
|
||||
@@ -1050,11 +1152,8 @@ void qla_nvme_abort_process_comp_status(struct abort_entry_24xx *abt, srb_t *ori
|
||||
/* BA_RJT was received for the ABTS */
|
||||
case CS_REJECT_RECEIVED:
|
||||
ql_dbg(ql_dbg_async, vha, 0xf09e,
|
||||
"BA_RJT was received for the ABTS rjt_vendorUnique = %u",
|
||||
abt->fw.ba_rjt_vendorUnique);
|
||||
ql_dbg(ql_dbg_async + ql_dbg_mbx, vha, 0xf09e,
|
||||
"ba_rjt_reasonCodeExpl = %u, ba_rjt_reasonCode = %u\n",
|
||||
abt->fw.ba_rjt_reasonCodeExpl, abt->fw.ba_rjt_reasonCode);
|
||||
"BA_RJT was received for the ABTS rjt_vendorUnique=%u, ba_rjt_reasonCodeExpl=%u, ba_rjt_reasonCode=%u\n",
|
||||
rjt_vendor_unique, rjt_reason_expl, rjt_reason_code);
|
||||
break;
|
||||
|
||||
case CS_COMPLETE:
|
||||
@@ -1101,37 +1200,61 @@ static void qla_nvme_fc_format_rjt(void *buf, u8 ls_cmd, u8 reason,
|
||||
rjt->rjt.vendor = vendor;
|
||||
}
|
||||
|
||||
/*
|
||||
* pt_ls4_request_ext overlays pt_ls4_request through exchange_address
|
||||
* (offsets 0-27 are byte-identical), so the common-header writes go
|
||||
* through one struct pt_ls4_request * view. The ext layout has a wider
|
||||
* __le16 vp_index and places tx_/rx_byte_count and dsd[] at different
|
||||
* offsets, so those assignments diverge per stride.
|
||||
*/
|
||||
static void qla_nvme_lsrjt_pt_iocb(struct scsi_qla_host *vha,
|
||||
struct pt_ls4_request *lsrjt_iocb,
|
||||
void *lsrjt_iocb,
|
||||
struct qla_nvme_lsrjt_pt_arg *a)
|
||||
{
|
||||
lsrjt_iocb->entry_type = PT_LS4_REQUEST;
|
||||
lsrjt_iocb->entry_count = 1;
|
||||
lsrjt_iocb->sys_define = 0;
|
||||
lsrjt_iocb->entry_status = 0;
|
||||
lsrjt_iocb->handle = QLA_SKIP_HANDLE;
|
||||
lsrjt_iocb->nport_handle = a->nport_handle;
|
||||
lsrjt_iocb->exchange_address = a->xchg_address;
|
||||
lsrjt_iocb->vp_index = a->vp_idx;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct pt_ls4_request *pkt = lsrjt_iocb;
|
||||
|
||||
lsrjt_iocb->control_flags = cpu_to_le16(a->control_flags);
|
||||
pkt->entry_type = PT_LS4_REQUEST;
|
||||
pkt->entry_count = 1;
|
||||
pkt->sys_define = 0;
|
||||
pkt->entry_status = 0;
|
||||
pkt->handle = QLA_SKIP_HANDLE;
|
||||
pkt->nport_handle = a->nport_handle;
|
||||
pkt->exchange_address = a->xchg_address;
|
||||
pkt->control_flags = cpu_to_le16(a->control_flags);
|
||||
pkt->tx_dseg_count = cpu_to_le16(1);
|
||||
pkt->rx_dseg_count = 0;
|
||||
|
||||
put_unaligned_le64(a->tx_addr, &lsrjt_iocb->dsd[0].address);
|
||||
lsrjt_iocb->dsd[0].length = cpu_to_le32(a->tx_byte_count);
|
||||
lsrjt_iocb->tx_dseg_count = cpu_to_le16(1);
|
||||
lsrjt_iocb->tx_byte_count = cpu_to_le32(a->tx_byte_count);
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct pt_ls4_request_ext *ext = lsrjt_iocb;
|
||||
|
||||
put_unaligned_le64(a->rx_addr, &lsrjt_iocb->dsd[1].address);
|
||||
lsrjt_iocb->dsd[1].length = 0;
|
||||
lsrjt_iocb->rx_dseg_count = 0;
|
||||
lsrjt_iocb->rx_byte_count = 0;
|
||||
ext->vp_index = cpu_to_le16(a->vp_idx);
|
||||
ext->tx_byte_count = cpu_to_le32(a->tx_byte_count);
|
||||
ext->rx_byte_count = 0;
|
||||
put_unaligned_le64(a->tx_addr, &ext->dsd[0].address);
|
||||
ext->dsd[0].length = cpu_to_le32(a->tx_byte_count);
|
||||
put_unaligned_le64(a->rx_addr, &ext->dsd[1].address);
|
||||
ext->dsd[1].length = 0;
|
||||
} else {
|
||||
pkt->vp_index = a->vp_idx;
|
||||
pkt->tx_byte_count = cpu_to_le32(a->tx_byte_count);
|
||||
pkt->rx_byte_count = 0;
|
||||
put_unaligned_le64(a->tx_addr, &pkt->dsd[0].address);
|
||||
pkt->dsd[0].length = cpu_to_le32(a->tx_byte_count);
|
||||
put_unaligned_le64(a->rx_addr, &pkt->dsd[1].address);
|
||||
pkt->dsd[1].length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocates from and advances the request ring, so the caller must hold
|
||||
* qp->qp_lock_ptr (the response-queue caller already holds it).
|
||||
*/
|
||||
static int
|
||||
qla_nvme_ls_reject_iocb(struct scsi_qla_host *vha, struct qla_qpair *qp,
|
||||
struct qla_nvme_lsrjt_pt_arg *a, bool is_xchg_terminate)
|
||||
{
|
||||
struct pt_ls4_request *lsrjt_iocb;
|
||||
void *lsrjt_iocb;
|
||||
|
||||
lsrjt_iocb = __qla2x00_alloc_iocbs(qp, NULL);
|
||||
if (!lsrjt_iocb) {
|
||||
@@ -1183,6 +1306,7 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
|
||||
{
|
||||
struct qla_nvme_unsol_ctx *uctx = item->purls_context;
|
||||
struct qla_nvme_lsrjt_pt_arg a;
|
||||
unsigned long flags;
|
||||
int ret = 1;
|
||||
|
||||
#if (IS_ENABLED(CONFIG_NVME_FC))
|
||||
@@ -1195,7 +1319,9 @@ qla2xxx_process_purls_pkt(struct scsi_qla_host *vha, struct purex_item *item)
|
||||
a.vp_idx = vha->vp_idx;
|
||||
a.nport_handle = uctx->nport_handle;
|
||||
a.xchg_address = uctx->exchange_address;
|
||||
spin_lock_irqsave(vha->hw->base_qpair->qp_lock_ptr, flags);
|
||||
qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true);
|
||||
spin_unlock_irqrestore(vha->hw->base_qpair->qp_lock_ptr, flags);
|
||||
list_del(&uctx->elem);
|
||||
kfree(uctx);
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ struct pt_ls4_rx_unsol {
|
||||
int qla_nvme_register_hba(struct scsi_qla_host *);
|
||||
int qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *);
|
||||
void qla_nvme_delete(struct scsi_qla_host *);
|
||||
void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *, struct pt_ls4_request *,
|
||||
struct req_que *);
|
||||
void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha, void *pkt,
|
||||
struct req_que *req);
|
||||
void qla24xx_async_gffid_sp_done(struct srb *sp, int);
|
||||
#endif
|
||||
|
||||
@@ -2663,7 +2663,7 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, __le32 *dwptr,
|
||||
|
||||
ret = qla2x00_load_ram(vha, optrom_dma,
|
||||
(ha->flash_data_off | faddr),
|
||||
OPTROM_BURST_DWORDS);
|
||||
OPTROM_BURST_DWORDS, 0);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0xb01e,
|
||||
"Unable to burst-write optrom segment "
|
||||
|
||||
@@ -429,7 +429,8 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req,
|
||||
qla_cpu_update(rsp->qpair, raw_smp_processor_id());
|
||||
ha->base_qpair->pdev = ha->pdev;
|
||||
|
||||
if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha))
|
||||
if (IS_QLA27XX(ha) || IS_QLA83XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha))
|
||||
ha->base_qpair->reqq_start_iocbs = qla_83xx_start_iocbs;
|
||||
}
|
||||
|
||||
@@ -501,6 +502,8 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req,
|
||||
|
||||
static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
|
||||
{
|
||||
size_t req_entry_size = qla_req_entry_size(ha);
|
||||
|
||||
if (IS_QLAFX00(ha)) {
|
||||
if (req && req->ring_fx00)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
@@ -508,8 +511,8 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
|
||||
req->ring_fx00, req->dma_fx00);
|
||||
} else if (req && req->ring)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
(req->length + 1) * sizeof(request_t),
|
||||
req->ring, req->dma);
|
||||
(req->length + 1) * req_entry_size,
|
||||
req->ring, req->dma);
|
||||
|
||||
if (req)
|
||||
kfree(req->outstanding_cmds);
|
||||
@@ -519,6 +522,8 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
|
||||
|
||||
static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
|
||||
{
|
||||
size_t rsp_entry_size = qla_rsp_entry_size(ha);
|
||||
|
||||
if (IS_QLAFX00(ha)) {
|
||||
if (rsp && rsp->ring_fx00)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
@@ -526,8 +531,8 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
|
||||
rsp->ring_fx00, rsp->dma_fx00);
|
||||
} else if (rsp && rsp->ring) {
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
(rsp->length + 1) * sizeof(response_t),
|
||||
rsp->ring, rsp->dma);
|
||||
(rsp->length + 1) * rsp_entry_size,
|
||||
rsp->ring, rsp->dma);
|
||||
}
|
||||
kfree(rsp);
|
||||
}
|
||||
@@ -2153,8 +2158,6 @@ qla2x00_iospace_config(struct qla_hw_data *ha)
|
||||
static int
|
||||
qla83xx_iospace_config(struct qla_hw_data *ha)
|
||||
{
|
||||
uint16_t msix;
|
||||
|
||||
if (pci_request_selected_regions(ha->pdev, ha->bars,
|
||||
QLA2XXX_DRIVER_NAME)) {
|
||||
ql_log_pci(ql_log_fatal, ha->pdev, 0x0117,
|
||||
@@ -2203,10 +2206,18 @@ qla83xx_iospace_config(struct qla_hw_data *ha)
|
||||
ha->msixbase = ioremap(pci_resource_start(ha->pdev, 2),
|
||||
pci_resource_len(ha->pdev, 2));
|
||||
if (ha->msixbase) {
|
||||
int msix_cnt;
|
||||
|
||||
/* Read MSIX vector size of the board */
|
||||
pci_read_config_word(ha->pdev,
|
||||
QLA_83XX_PCI_MSIX_CONTROL, &msix);
|
||||
ha->msix_count = (msix & PCI_MSIX_FLAGS_QSIZE) + 1;
|
||||
msix_cnt = pci_msix_vec_count(ha->pdev);
|
||||
if (msix_cnt <= 0) {
|
||||
ql_log_pci(ql_log_warn, ha->pdev, 0x0120,
|
||||
"Failed to read MSI-X count (%d), falling back to base vectors.\n",
|
||||
msix_cnt);
|
||||
goto mqiobase_exit;
|
||||
}
|
||||
ha->msix_count = msix_cnt;
|
||||
|
||||
/*
|
||||
* By default, driver uses at least two msix vectors
|
||||
* (default & rspq)
|
||||
@@ -2633,6 +2644,66 @@ static struct isp_operations qla27xx_isp_ops = {
|
||||
.initialize_adapter = qla2x00_initialize_adapter,
|
||||
};
|
||||
|
||||
static void *
|
||||
qla29xx_read_optrom_stub(struct scsi_qla_host *vha, void *buf,
|
||||
uint32_t offset, uint32_t length)
|
||||
{
|
||||
ql_dbg(ql_dbg_init, vha, 0x0191,
|
||||
"read_optrom not supported on 29xx, use read_optrom_region.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
qla29xx_write_optrom_stub(struct scsi_qla_host *vha, void *buf,
|
||||
uint32_t offset, uint32_t length)
|
||||
{
|
||||
ql_dbg(ql_dbg_init, vha, 0x0192,
|
||||
"write_optrom not supported on 29xx, use write_optrom_region.\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
static struct isp_operations qla29xx_isp_ops = {
|
||||
.pci_config = qla25xx_pci_config,
|
||||
.reset_chip = qla24xx_reset_chip,
|
||||
.chip_diag = qla24xx_chip_diag,
|
||||
.config_rings = qla24xx_config_rings,
|
||||
.reset_adapter = qla24xx_reset_adapter,
|
||||
.nvram_config = qla81xx_nvram_config,
|
||||
.update_fw_options = qla24xx_update_fw_options,
|
||||
.load_risc = qla29xx_load_risc,
|
||||
.pci_info_str = qla24xx_pci_info_str,
|
||||
.fw_version_str = qla24xx_fw_version_str,
|
||||
.intr_handler = qla24xx_intr_handler,
|
||||
.enable_intrs = qla24xx_enable_intrs,
|
||||
.disable_intrs = qla24xx_disable_intrs,
|
||||
.abort_command = qla24xx_abort_command,
|
||||
.target_reset = qla24xx_abort_target,
|
||||
.lun_reset = qla24xx_lun_reset,
|
||||
.fabric_login = qla24xx_login_fabric,
|
||||
.fabric_logout = qla24xx_fabric_logout,
|
||||
.calc_req_entries = NULL,
|
||||
.build_iocbs = NULL,
|
||||
.prep_ms_iocb = qla24xx_prep_ms_iocb,
|
||||
.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb,
|
||||
.read_nvram = NULL,
|
||||
.write_nvram = NULL,
|
||||
.fw_dump = qla27xx_fwdump,
|
||||
.mpi_fw_dump = qla27xx_mpi_fwdump,
|
||||
.beacon_on = qla24xx_beacon_on,
|
||||
.beacon_off = qla24xx_beacon_off,
|
||||
.beacon_blink = qla83xx_beacon_blink,
|
||||
.read_optrom = qla29xx_read_optrom_stub,
|
||||
.write_optrom = qla29xx_write_optrom_stub,
|
||||
.read_optrom_region = qla29xx_read_optrom_data,
|
||||
.write_optrom_region = qla29xx_write_optrom_data,
|
||||
.get_flash_version = qla24xx_get_flash_version,
|
||||
.start_scsi = qla24xx_dif_start_scsi,
|
||||
.start_scsi_mq = qla2xxx_dif_start_scsi_mq,
|
||||
.abort_isp = qla2x00_abort_isp,
|
||||
.iospace_config = qla83xx_iospace_config,
|
||||
.initialize_adapter = qla2x00_initialize_adapter,
|
||||
};
|
||||
|
||||
static inline void
|
||||
qla2x00_set_isp_flags(struct qla_hw_data *ha)
|
||||
{
|
||||
@@ -2796,6 +2867,20 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
|
||||
ha->device_type |= DT_T10_PI;
|
||||
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
|
||||
break;
|
||||
case PCI_DEVICE_ID_QLOGIC_ISP2099:
|
||||
case PCI_DEVICE_ID_QLOGIC_ISP2299:
|
||||
case PCI_DEVICE_ID_QLOGIC_ISP2091:
|
||||
case PCI_DEVICE_ID_QLOGIC_ISP2291:
|
||||
ha->isp_type |= DT_ISP2299;
|
||||
ha->isp_type |= DT_ISP2099;
|
||||
ha->isp_type |= DT_ISP2091;
|
||||
ha->isp_type |= DT_ISP2291;
|
||||
ha->device_type |= DT_ZIO_SUPPORTED;
|
||||
ha->device_type |= DT_FWI2;
|
||||
ha->device_type |= DT_IIDMA;
|
||||
ha->device_type |= DT_T10_PI;
|
||||
ha->fw_srisc_address = RISC_START_ADDRESS_2400;
|
||||
break;
|
||||
}
|
||||
|
||||
if (IS_QLA82XX(ha))
|
||||
@@ -2806,12 +2891,11 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
|
||||
if (ha->port_no == 0) {
|
||||
/* None of INT[A|B|C|D] may be virtualized by vfio */
|
||||
ha->port_no = PCI_FUNC(ha->pdev->devfn);
|
||||
} else if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
ha->port_no--;
|
||||
} else {
|
||||
if (IS_QLA25XX(ha) || IS_QLA2031(ha) ||
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
ha->port_no--;
|
||||
else
|
||||
ha->port_no = !(ha->port_no & 1);
|
||||
ha->port_no = !(ha->port_no & 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2941,7 +3025,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2081 ||
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2281 ||
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2089 ||
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2289) {
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2289 ||
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2099 ||
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2299 ||
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2091 ||
|
||||
pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2291) {
|
||||
bars = pci_select_bars(pdev, IORESOURCE_MEM);
|
||||
mem_only = 1;
|
||||
ql_dbg_pci(ql_dbg_init, pdev, 0x0007,
|
||||
@@ -3003,7 +3091,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
|
||||
/* Set EEH reset type to fundamental if required by hba */
|
||||
if (IS_QLA24XX(ha) || IS_QLA25XX(ha) || IS_QLA81XX(ha) ||
|
||||
IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
|
||||
IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha) ||
|
||||
IS_QLA29XX(ha))
|
||||
pdev->needs_freset = 1;
|
||||
|
||||
ha->prev_topology = 0;
|
||||
@@ -3200,6 +3289,23 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
ha->flash_data_off = FARX_ACCESS_FLASH_DATA_28XX;
|
||||
ha->nvram_conf_off = ~0;
|
||||
ha->nvram_data_off = ~0;
|
||||
} else if (IS_QLA29XX(ha)) {
|
||||
ha->portnum = PCI_FUNC(ha->pdev->devfn);
|
||||
ha->max_fibre_devices = MAX_FIBRE_DEVICES_2400;
|
||||
ha->mbx_count = MAILBOX_REGISTER_COUNT;
|
||||
req_length = REQUEST_ENTRY_CNT_83XX;
|
||||
rsp_length = RESPONSE_ENTRY_CNT_83XX;
|
||||
ha->max_loop_id = SNS_LAST_LOOP_ID_2300;
|
||||
ha->init_cb_size = sizeof(struct mid_init_cb_81xx);
|
||||
ha->gid_list_info_size = 8;
|
||||
ha->optrom_size = OPTROM_SIZE_28XX;
|
||||
ha->nvram_npiv_size = QLA_MAX_VPORTS_QLA25XX;
|
||||
ha->isp_ops = &qla29xx_isp_ops;
|
||||
ha->flash_conf_off = ~0;
|
||||
ha->flash_data_off = ~0;
|
||||
ha->nvram_conf_off = ~0;
|
||||
ha->nvram_data_off = ~0;
|
||||
ha->flt_segment_length = QLA_SEGMENT_LENGTH;
|
||||
}
|
||||
|
||||
ql_dbg_pci(ql_dbg_init, pdev, 0x001e,
|
||||
@@ -3378,7 +3484,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
rsp->rsp_q_in = &ha->iobase->isp24.rsp_q_in;
|
||||
rsp->rsp_q_out = &ha->iobase->isp24.rsp_q_out;
|
||||
if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha)) {
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
req->req_q_in = &ha->mqiobase->isp25mq.req_q_in;
|
||||
req->req_q_out = &ha->mqiobase->isp25mq.req_q_out;
|
||||
rsp->rsp_q_in = &ha->mqiobase->isp25mq.rsp_q_in;
|
||||
@@ -3738,7 +3844,7 @@ qla2x00_shutdown(struct pci_dev *pdev)
|
||||
qla2x00_disable_eft_trace(vha);
|
||||
|
||||
if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha)) {
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
if (ha->flags.fw_started)
|
||||
qla2x00_abort_isp_cleanup(vha);
|
||||
} else {
|
||||
@@ -3903,7 +4009,7 @@ qla2x00_remove_one(struct pci_dev *pdev)
|
||||
return;
|
||||
|
||||
if (IS_QLA25XX(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha)) {
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
if (ha->flags.fw_started)
|
||||
qla2x00_abort_isp_cleanup(base_vha);
|
||||
} else if (!IS_QLAFX00(ha)) {
|
||||
@@ -4152,6 +4258,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
{
|
||||
char name[16];
|
||||
int rc;
|
||||
size_t req_entry_size = qla_req_entry_size(ha);
|
||||
size_t rsp_entry_size = qla_rsp_entry_size(ha);
|
||||
|
||||
if (QLA_TGT_MODE_ENABLED() || EDIF_CAP(ha)) {
|
||||
ha->vp_map = kzalloc_objs(struct qla_vp_map,
|
||||
@@ -4181,7 +4289,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
if (!ha->srb_mempool)
|
||||
goto fail_free_gid_list;
|
||||
|
||||
if (IS_P3P_TYPE(ha) || IS_QLA27XX(ha) || (ql2xsecenable && IS_QLA28XX(ha))) {
|
||||
if (IS_P3P_TYPE(ha) || IS_QLA27XX(ha) ||
|
||||
(ql2xsecenable && (IS_QLA28XX(ha) || IS_QLA29XX(ha)))) {
|
||||
/* Allocate cache for CT6 Ctx. */
|
||||
if (!ctx_cachep) {
|
||||
ctx_cachep = kmem_cache_create("qla2xxx_ctx",
|
||||
@@ -4215,7 +4324,8 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
"init_cb=%p gid_list=%p, srb_mempool=%p s_dma_pool=%p.\n",
|
||||
ha->init_cb, ha->gid_list, ha->srb_mempool, ha->s_dma_pool);
|
||||
|
||||
if (IS_P3P_TYPE(ha) || ql2xenabledif || (IS_QLA28XX(ha) && ql2xsecenable)) {
|
||||
if (IS_P3P_TYPE(ha) || ql2xenabledif ||
|
||||
((IS_QLA28XX(ha) || IS_QLA29XX(ha)) && ql2xsecenable)) {
|
||||
ha->dl_dma_pool = dma_pool_create(name, &ha->pdev->dev,
|
||||
DSD_LIST_DMA_POOL_SIZE, 8, 0);
|
||||
if (!ha->dl_dma_pool) {
|
||||
@@ -4347,13 +4457,17 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
}
|
||||
(*req)->length = req_len;
|
||||
(*req)->ring = dma_alloc_coherent(&ha->pdev->dev,
|
||||
((*req)->length + 1) * sizeof(request_t),
|
||||
((*req)->length + 1) * req_entry_size,
|
||||
&(*req)->dma, GFP_KERNEL);
|
||||
if (!(*req)->ring) {
|
||||
ql_log_pci(ql_log_fatal, ha->pdev, 0x0029,
|
||||
"Failed to allocate memory for req_ring.\n");
|
||||
goto fail_req_ring;
|
||||
}
|
||||
if (IS_QLA29XX(ha)) {
|
||||
(*req)->ring_ext = (struct request_ext *)(*req)->ring;
|
||||
(*req)->ring_ext_ptr = (*req)->ring_ext;
|
||||
}
|
||||
/* Allocate memory for response ring */
|
||||
*rsp = kzalloc_obj(struct rsp_que);
|
||||
if (!*rsp) {
|
||||
@@ -4364,13 +4478,17 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
(*rsp)->hw = ha;
|
||||
(*rsp)->length = rsp_len;
|
||||
(*rsp)->ring = dma_alloc_coherent(&ha->pdev->dev,
|
||||
((*rsp)->length + 1) * sizeof(response_t),
|
||||
((*rsp)->length + 1) * rsp_entry_size,
|
||||
&(*rsp)->dma, GFP_KERNEL);
|
||||
if (!(*rsp)->ring) {
|
||||
ql_log_pci(ql_log_fatal, ha->pdev, 0x002b,
|
||||
"Failed to allocate memory for rsp_ring.\n");
|
||||
goto fail_rsp_ring;
|
||||
}
|
||||
if (IS_QLA29XX(ha)) {
|
||||
(*rsp)->ring_ext = (struct response_ext *)(*rsp)->ring;
|
||||
(*rsp)->ring_ext_ptr = (*rsp)->ring_ext;
|
||||
}
|
||||
(*req)->rsp = *rsp;
|
||||
(*rsp)->req = *req;
|
||||
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x002c,
|
||||
@@ -4392,7 +4510,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
|
||||
/* Get consistent memory allocated for EX-INIT-CB. */
|
||||
if (IS_CNA_CAPABLE(ha) || IS_QLA2031(ha) || IS_QLA27XX(ha) ||
|
||||
IS_QLA28XX(ha)) {
|
||||
IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
ha->ex_init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
|
||||
&ha->ex_init_cb_dma);
|
||||
if (!ha->ex_init_cb)
|
||||
@@ -4402,7 +4520,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
}
|
||||
|
||||
/* Get consistent memory allocated for Special Features-CB. */
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha) || IS_QLA29XX(ha)) {
|
||||
ha->sf_init_cb = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL,
|
||||
&ha->sf_init_cb_dma);
|
||||
if (!ha->sf_init_cb)
|
||||
@@ -4451,6 +4569,14 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
goto fail_flt_buffer;
|
||||
}
|
||||
|
||||
ha->flt_data = vzalloc(sizeof(struct qla_flash_layout) +
|
||||
(sizeof(struct qla_flt_region_data) * FLT_MAX_REGIONS));
|
||||
if (!ha->flt_data) {
|
||||
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x001a,
|
||||
"Unable to allocate memory for mini FLT data.\n");
|
||||
goto fail_flt;
|
||||
}
|
||||
|
||||
/* allocate the purex dma pool */
|
||||
ha->purex_dma_pool = dma_pool_create(name, &ha->pdev->dev,
|
||||
ELS_MAX_PAYLOAD, 8, 0);
|
||||
@@ -4458,7 +4584,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
if (!ha->purex_dma_pool) {
|
||||
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b,
|
||||
"Unable to allocate purex_dma_pool.\n");
|
||||
goto fail_flt;
|
||||
goto fail_flt_data;
|
||||
}
|
||||
|
||||
ha->elsrej.size = sizeof(struct fc_els_ls_rjt) + 16;
|
||||
@@ -4491,6 +4617,9 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
ha->elsrej.c, ha->elsrej.cdma);
|
||||
fail_elsrej:
|
||||
dma_pool_destroy(ha->purex_dma_pool);
|
||||
fail_flt_data:
|
||||
vfree(ha->flt_data);
|
||||
ha->flt_data = NULL;
|
||||
fail_flt:
|
||||
dma_free_coherent(&ha->pdev->dev, sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE,
|
||||
ha->flt, ha->flt_dma);
|
||||
@@ -4509,16 +4638,18 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
fail_ex_init_cb:
|
||||
kfree(ha->npiv_info);
|
||||
fail_npiv_info:
|
||||
dma_free_coherent(&ha->pdev->dev, ((*rsp)->length + 1) *
|
||||
sizeof(response_t), (*rsp)->ring, (*rsp)->dma);
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
((*rsp)->length + 1) * rsp_entry_size,
|
||||
(*rsp)->ring, (*rsp)->dma);
|
||||
(*rsp)->ring = NULL;
|
||||
(*rsp)->dma = 0;
|
||||
fail_rsp_ring:
|
||||
kfree(*rsp);
|
||||
*rsp = NULL;
|
||||
fail_rsp:
|
||||
dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) *
|
||||
sizeof(request_t), (*req)->ring, (*req)->dma);
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
((*req)->length + 1) * req_entry_size,
|
||||
(*req)->ring, (*req)->dma);
|
||||
(*req)->ring = NULL;
|
||||
(*req)->dma = 0;
|
||||
fail_req_ring:
|
||||
@@ -4556,12 +4687,12 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
}
|
||||
|
||||
fail_dif_bundl_dma_pool:
|
||||
if (IS_QLA82XX(ha) || ql2xenabledif) {
|
||||
if (IS_QLA82XX(ha) || IS_QLA29XX(ha) || ql2xenabledif) {
|
||||
dma_pool_destroy(ha->fcp_cmnd_dma_pool);
|
||||
ha->fcp_cmnd_dma_pool = NULL;
|
||||
}
|
||||
fail_dl_dma_pool:
|
||||
if (IS_QLA82XX(ha) || ql2xenabledif) {
|
||||
if (IS_QLA82XX(ha) || IS_QLA29XX(ha) || ql2xenabledif) {
|
||||
dma_pool_destroy(ha->dl_dma_pool);
|
||||
ha->dl_dma_pool = NULL;
|
||||
}
|
||||
@@ -4571,6 +4702,7 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
fail_free_nvram:
|
||||
kfree(ha->nvram);
|
||||
ha->nvram = NULL;
|
||||
ha->fiv = NULL;
|
||||
fail_free_ctx_mempool:
|
||||
mempool_destroy(ha->ctx_mempool);
|
||||
ha->ctx_mempool = NULL;
|
||||
@@ -4926,6 +5058,10 @@ qla2x00_mem_free(struct qla_hw_data *ha)
|
||||
ha->flt = NULL;
|
||||
ha->flt_dma = 0;
|
||||
|
||||
if (ha->flt_data)
|
||||
vfree(ha->flt_data);
|
||||
ha->flt_data = NULL;
|
||||
|
||||
if (ha->ms_iocb)
|
||||
dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
|
||||
ha->ms_iocb = NULL;
|
||||
@@ -5032,6 +5168,7 @@ qla2x00_mem_free(struct qla_hw_data *ha)
|
||||
ha->optrom_buffer = NULL;
|
||||
kfree(ha->nvram);
|
||||
ha->nvram = NULL;
|
||||
ha->fiv = NULL;
|
||||
kfree(ha->npiv_info);
|
||||
ha->npiv_info = NULL;
|
||||
kfree(ha->swl);
|
||||
@@ -6005,13 +6142,15 @@ qla83xx_idc_lock(scsi_qla_host_t *base_vha, uint16_t requester_id)
|
||||
}
|
||||
|
||||
static bool
|
||||
qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha,
|
||||
struct purex_entry_24xx *purex)
|
||||
qla25xx_rdp_rsp_reduce_size(struct scsi_qla_host *vha, void *pkt)
|
||||
{
|
||||
struct purex_entry_24xx *purex = pkt;
|
||||
char fwstr[16];
|
||||
u32 sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0];
|
||||
u32 sid;
|
||||
struct port_database_24xx *pdb;
|
||||
|
||||
sid = purex->s_id[2] << 16 | purex->s_id[1] << 8 | purex->s_id[0];
|
||||
|
||||
/* Domain Controller is always logged-out. */
|
||||
/* if RDP request is not from Domain Controller: */
|
||||
if (sid != 0xfffc01)
|
||||
@@ -6076,15 +6215,28 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
|
||||
uint8_t *sfp = NULL;
|
||||
uint16_t sfp_flags = 0;
|
||||
uint rsp_payload_length = sizeof(*rsp_payload);
|
||||
u16 vp_idx;
|
||||
size_t purex_sz;
|
||||
size_t rsp_els_sz;
|
||||
void *rsp_els_pkt = NULL;
|
||||
int rval;
|
||||
|
||||
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0180,
|
||||
"%s: Enter\n", __func__);
|
||||
|
||||
if (IS_QLA29XX(ha)) {
|
||||
vp_idx = le16_to_cpu(
|
||||
((struct purex_entry_24xx_ext *)purex)->vp_idx);
|
||||
purex_sz = sizeof(struct purex_entry_24xx_ext);
|
||||
} else {
|
||||
vp_idx = purex->vp_idx;
|
||||
purex_sz = sizeof(*purex);
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0181,
|
||||
"-------- ELS REQ -------\n");
|
||||
ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0182,
|
||||
purex, sizeof(*purex));
|
||||
purex, purex_sz);
|
||||
|
||||
if (qla25xx_rdp_rsp_reduce_size(vha, purex)) {
|
||||
rsp_payload_length =
|
||||
@@ -6094,13 +6246,19 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
|
||||
rsp_payload_length);
|
||||
}
|
||||
|
||||
rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els),
|
||||
if (IS_QLA29XX(ha))
|
||||
rsp_els_sz = sizeof(struct els_entry_24xx_ext);
|
||||
else
|
||||
rsp_els_sz = sizeof(struct els_entry_24xx);
|
||||
|
||||
rsp_els_pkt = dma_alloc_coherent(&ha->pdev->dev, rsp_els_sz,
|
||||
&rsp_els_dma, GFP_KERNEL);
|
||||
if (!rsp_els) {
|
||||
if (!rsp_els_pkt) {
|
||||
ql_log(ql_log_warn, vha, 0x0183,
|
||||
"Failed allocate dma buffer ELS RSP.\n");
|
||||
"Failed to allocate dma buffer ELS RSP.\n");
|
||||
goto dealloc;
|
||||
}
|
||||
rsp_els = rsp_els_pkt;
|
||||
|
||||
rsp_payload = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_payload),
|
||||
&rsp_payload_dma, GFP_KERNEL);
|
||||
@@ -6124,12 +6282,12 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
|
||||
rsp_els->handle = 0;
|
||||
rsp_els->nport_handle = purex->nport_handle;
|
||||
rsp_els->tx_dsd_count = cpu_to_le16(1);
|
||||
rsp_els->vp_index = purex->vp_idx;
|
||||
rsp_els->sof_type = EST_SOFI3;
|
||||
rsp_els->rx_xchg_address = purex->rx_xchg_addr;
|
||||
rsp_els->rx_dsd_count = 0;
|
||||
rsp_els->opcode = purex->els_frame_payload[0];
|
||||
|
||||
qla_els_set_vp_sof(vha, rsp_els_pkt, vp_idx);
|
||||
|
||||
rsp_els->d_id[0] = purex->s_id[0];
|
||||
rsp_els->d_id[1] = purex->s_id[1];
|
||||
rsp_els->d_id[2] = purex->s_id[2];
|
||||
@@ -6429,13 +6587,13 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
|
||||
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0184,
|
||||
"-------- ELS RSP -------\n");
|
||||
ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0185,
|
||||
rsp_els, sizeof(*rsp_els));
|
||||
rsp_els_pkt, rsp_els_sz);
|
||||
ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0186,
|
||||
"-------- ELS RSP PAYLOAD -------\n");
|
||||
ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0187,
|
||||
rsp_payload, rsp_payload_length);
|
||||
|
||||
rval = qla2x00_issue_iocb(vha, rsp_els, rsp_els_dma, 0);
|
||||
rval = qla2x00_issue_iocb(vha, rsp_els_pkt, rsp_els_dma, 0);
|
||||
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x0188,
|
||||
@@ -6459,9 +6617,9 @@ void qla24xx_process_purex_rdp(struct scsi_qla_host *vha,
|
||||
if (rsp_payload)
|
||||
dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_payload),
|
||||
rsp_payload, rsp_payload_dma);
|
||||
if (rsp_els)
|
||||
dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els),
|
||||
rsp_els, rsp_els_dma);
|
||||
if (rsp_els_pkt)
|
||||
dma_free_coherent(&ha->pdev->dev, rsp_els_sz,
|
||||
rsp_els_pkt, rsp_els_dma);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -7621,6 +7779,7 @@ qla2x00_timer(struct timer_list *t)
|
||||
#define FW_ISP8031 9
|
||||
#define FW_ISP27XX 10
|
||||
#define FW_ISP28XX 11
|
||||
#define FW_ISP29XX 12
|
||||
|
||||
#define FW_FILE_ISP21XX "ql2100_fw.bin"
|
||||
#define FW_FILE_ISP22XX "ql2200_fw.bin"
|
||||
@@ -7634,6 +7793,7 @@ qla2x00_timer(struct timer_list *t)
|
||||
#define FW_FILE_ISP8031 "ql8300_fw.bin"
|
||||
#define FW_FILE_ISP27XX "ql2700_fw.bin"
|
||||
#define FW_FILE_ISP28XX "ql2800_fw.bin"
|
||||
#define FW_FILE_ISP29XX "ql2900_fw.bin"
|
||||
|
||||
|
||||
static DEFINE_MUTEX(qla_fw_lock);
|
||||
@@ -7651,6 +7811,7 @@ static struct fw_blob qla_fw_blobs[] = {
|
||||
{ .name = FW_FILE_ISP8031, },
|
||||
{ .name = FW_FILE_ISP27XX, },
|
||||
{ .name = FW_FILE_ISP28XX, },
|
||||
{ .name = FW_FILE_ISP29XX, },
|
||||
{ .name = NULL, },
|
||||
};
|
||||
|
||||
@@ -7684,6 +7845,8 @@ qla2x00_request_firmware(scsi_qla_host_t *vha)
|
||||
blob = &qla_fw_blobs[FW_ISP27XX];
|
||||
} else if (IS_QLA28XX(ha)) {
|
||||
blob = &qla_fw_blobs[FW_ISP28XX];
|
||||
} else if (IS_QLA29XX(ha)) {
|
||||
blob = &qla_fw_blobs[FW_ISP29XX];
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
@@ -8160,6 +8323,10 @@ static const struct pci_device_id qla2xxx_pci_tbl[] = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2281) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2089) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2289) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2099) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2299) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2091) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2291) },
|
||||
{ 0 },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl);
|
||||
@@ -8195,17 +8362,21 @@ qla2x00_module_init(void)
|
||||
BUILD_BUG_ON(sizeof(ms_iocb_entry_t) != 64);
|
||||
BUILD_BUG_ON(sizeof(request_t) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct abort_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct abort_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct abort_iocb_entry_fx00) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct abts_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct abts_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct access_chip_84xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct access_chip_rsp_84xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct cmd_bidir) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct cmd_nvme) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct cmd_nvme_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct cmd_type_6) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct cmd_type_7) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct cmd_type_7_fx00) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct cmd_type_crc_2) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct ct_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct ct_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct ct_fdmi1_hba_attributes) != 2604);
|
||||
BUILD_BUG_ON(sizeof(struct ct_fdmi2_hba_attributes) != 4424);
|
||||
BUILD_BUG_ON(sizeof(struct ct_fdmi2_port_attributes) != 4164);
|
||||
@@ -8219,20 +8390,26 @@ qla2x00_module_init(void)
|
||||
BUILD_BUG_ON(sizeof(struct device_reg_82xx) != 1288);
|
||||
BUILD_BUG_ON(sizeof(struct device_reg_fx00) != 216);
|
||||
BUILD_BUG_ON(sizeof(struct els_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct els_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct els_sts_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct els_sts_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct fxdisc_entry_fx00) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct imm_ntfy_from_isp) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct init_cb_24xx) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct init_cb_81xx) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct logio_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct logio_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct mbx_entry) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct mid_init_cb_24xx) != 5252);
|
||||
BUILD_BUG_ON(sizeof(struct mrk_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct mrk_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct nvram_24xx) != 512);
|
||||
BUILD_BUG_ON(sizeof(struct nvram_81xx) != 512);
|
||||
BUILD_BUG_ON(sizeof(struct pt_ls4_request) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct pt_ls4_request_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct pt_ls4_rx_unsol) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct purex_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct purex_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct qla2100_fw_dump) != 123634);
|
||||
BUILD_BUG_ON(sizeof(struct qla2300_fw_dump) != 136100);
|
||||
BUILD_BUG_ON(sizeof(struct qla24xx_fw_dump) != 37976);
|
||||
@@ -8256,17 +8433,23 @@ qla2x00_module_init(void)
|
||||
BUILD_BUG_ON(sizeof(struct rdp_rsp_payload) != 336);
|
||||
BUILD_BUG_ON(sizeof(struct sns_cmd_pkt) != 2064);
|
||||
BUILD_BUG_ON(sizeof(struct sts_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct sts_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct tsk_mgmt_entry_fx00) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct verify_chip_entry_84xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct verify_chip_rsp_84xx) != 52);
|
||||
BUILD_BUG_ON(sizeof(struct vf_evfp_entry_24xx) != 56);
|
||||
BUILD_BUG_ON(sizeof(struct vp_config_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct vp_config_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct vp_ctrl_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(struct vp_rpt_id_entry_24xx) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct vp_rpt_id_entry_24xx_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(sts21_entry_t) != 64);
|
||||
BUILD_BUG_ON(sizeof(sts22_entry_t) != 64);
|
||||
BUILD_BUG_ON(sizeof(sts_cont_entry_t) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct sts_cont_entry_ext) != 128);
|
||||
BUILD_BUG_ON(sizeof(sts_entry_t) != 64);
|
||||
BUILD_BUG_ON(sizeof(sw_info_t) != 32);
|
||||
BUILD_BUG_ON(sizeof(target_id_t) != 2);
|
||||
@@ -8386,3 +8569,4 @@ MODULE_FIRMWARE(FW_FILE_ISP2300);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP2322);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP24XX);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP25XX);
|
||||
MODULE_FIRMWARE(FW_FILE_ISP29XX);
|
||||
|
||||
@@ -10,6 +10,654 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
/**
|
||||
* qla29xx_get_flt_layout - Retrieve the flash layout table (FLT) for QLA29xx.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
*
|
||||
* This function reads and validates the FLT structure from the flash memory.
|
||||
* It extracts region information and updates the hardware data structure.
|
||||
*/
|
||||
static void
|
||||
qla29xx_get_flt_layout(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flash_layout *flt_layout = ha->flt_data;
|
||||
struct qla_flt_region_header *flt_header = &flt_layout->flt_header;
|
||||
struct qla_flt_region_data *region = &flt_layout->region[0];
|
||||
uint32_t flt_options = 0;
|
||||
uint32_t flt_size;
|
||||
uint32_t cnt, chksum;
|
||||
uint16_t reg_cnt, i;
|
||||
__le32 *wptr;
|
||||
void *buf = NULL;
|
||||
|
||||
flt_size = sizeof(struct qla_flt_region_header);
|
||||
wptr = (__force __le32 *)ha->flt_data;
|
||||
|
||||
buf = qla29xx_read_optrom_data(vha, FLT_REG_MINI_FLT, flt_options,
|
||||
ha->flt_data, 0, flt_size);
|
||||
if (!buf) {
|
||||
ql_log(ql_log_warn, vha, 0x007b,
|
||||
"Failed to read FLT information.\n");
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
|
||||
"Contents of Flash Layout (0x%x):\n", flt_size);
|
||||
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112,
|
||||
ha->flt_data, flt_size);
|
||||
|
||||
/* check flt version checksum and other info */
|
||||
if ((le32_to_cpu(*wptr) == 0xffffffff) ||
|
||||
flt_header->version != cpu_to_le32(FLT_HDR_VERSION)) {
|
||||
ql_log(ql_log_warn, vha, 0x007c,
|
||||
"Unsupported FLT detected: version=0x%x length=0x%x signature=0x%x region_count=0x%x checksum=0x%x.\n",
|
||||
le32_to_cpu(flt_header->version),
|
||||
le32_to_cpu(flt_header->length),
|
||||
le32_to_cpu(flt_header->signature),
|
||||
le16_to_cpu(flt_header->region_count),
|
||||
le32_to_cpu(flt_header->checksum));
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
reg_cnt = le16_to_cpu(flt_header->region_count);
|
||||
if (reg_cnt > FLT_MAX_REGIONS)
|
||||
goto exit_flt;
|
||||
|
||||
if (le16_to_cpu(flt_header->region_size) !=
|
||||
sizeof(struct qla_flt_region_data)) {
|
||||
ql_log(ql_log_warn, vha, 0x0082,
|
||||
"Unsupported FLT region size 0x%x (expected 0x%zx).\n",
|
||||
le16_to_cpu(flt_header->region_size),
|
||||
sizeof(struct qla_flt_region_data));
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
flt_size = sizeof(struct qla_flash_layout) +
|
||||
(reg_cnt * le16_to_cpu(flt_header->region_size));
|
||||
if (flt_size > sizeof(struct qla_flash_layout) +
|
||||
sizeof(struct qla_flt_region_data) * FLT_DATA_MAX_REGIONS) {
|
||||
ql_log(ql_log_warn, vha, 0x007d,
|
||||
"FLT size 0x%x exceeds buffer, region_size=0x%x.\n",
|
||||
flt_size, le16_to_cpu(flt_header->region_size));
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
buf = qla29xx_read_optrom_data(vha, FLT_REG_MINI_FLT, flt_options,
|
||||
ha->flt_data, 0, flt_size);
|
||||
if (!buf) {
|
||||
ql_log(ql_log_warn, vha, 0x007b,
|
||||
"Failed to read FLT information.\n");
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
cnt = le32_to_cpu(flt_header->length) / sizeof(*wptr);
|
||||
if (cnt > flt_size / sizeof(*wptr)) {
|
||||
ql_log(ql_log_warn, vha, 0x007e,
|
||||
"FLT length 0x%x exceeds read size 0x%x, rejecting.\n",
|
||||
le32_to_cpu(flt_header->length), flt_size);
|
||||
goto exit_flt;
|
||||
}
|
||||
for (chksum = 0; cnt--; wptr++)
|
||||
chksum += le32_to_cpu(*wptr);
|
||||
if (chksum) {
|
||||
ql_log(ql_log_fatal, vha, 0x007f,
|
||||
"Inconsistent FLT detected: version=0x%x length=0x%x signature=0x%x checksum=0x%x.\n",
|
||||
le32_to_cpu(flt_header->version),
|
||||
le32_to_cpu(flt_header->length),
|
||||
le32_to_cpu(flt_header->signature),
|
||||
le32_to_cpu(flt_header->checksum));
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x007f,
|
||||
"FLT detected: version=0x%08x length=0x%08x signature=0x%08x region_count=0x%04x region_len=0x%04x segment_len=0x%08x checksum=0x%08x.\n",
|
||||
le32_to_cpu(flt_header->version),
|
||||
le32_to_cpu(flt_header->length),
|
||||
le32_to_cpu(flt_header->signature),
|
||||
le16_to_cpu(flt_header->region_count),
|
||||
le16_to_cpu(flt_header->region_size),
|
||||
le32_to_cpu(flt_header->segment_size),
|
||||
le32_to_cpu(flt_header->checksum));
|
||||
|
||||
for (i = 0; reg_cnt; i++, reg_cnt--) {
|
||||
region = &flt_layout->region[i];
|
||||
ql_dbg(ql_dbg_init, vha, 0x0080,
|
||||
"FLT[%03x]: len=0x%08x version=0x%08x attr=0x%02x.\n",
|
||||
le16_to_cpu(region->region_code),
|
||||
le32_to_cpu(region->image_length),
|
||||
le32_to_cpu(region->version),
|
||||
le32_to_cpu(region->attribute));
|
||||
if (le16_to_cpu(region->region_code) == FLT_REG_FW_DUMP_TMPLT) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x0080,
|
||||
"%s: %d: Found FW dump template", __func__, __LINE__);
|
||||
ha->fw_dump_tmplt_len = le32_to_cpu(region->image_length);
|
||||
}
|
||||
}
|
||||
|
||||
if (le32_to_cpu(flt_header->segment_size) >= sizeof(uint32_t)) {
|
||||
ha->flt_segment_length = le32_to_cpu(flt_header->segment_size);
|
||||
} else {
|
||||
ql_log(ql_log_warn, vha, 0x0081,
|
||||
"FLT segment size 0x%x too small, using default 0x%x.\n",
|
||||
le32_to_cpu(flt_header->segment_size), QLA_SEGMENT_LENGTH);
|
||||
ha->flt_segment_length = QLA_SEGMENT_LENGTH;
|
||||
}
|
||||
ha->flags.valid_flt = true;
|
||||
return;
|
||||
|
||||
exit_flt:
|
||||
ha->flt_segment_length = QLA_SEGMENT_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_get_fdt_info - Retrieve flash descriptor table (FDT) information.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
*
|
||||
* This function reads and validates the FDT structure from the flash memory.
|
||||
* It extracts manufacturer and device-specific information and updates
|
||||
* the hardware data structure.
|
||||
*/
|
||||
static void
|
||||
qla29xx_get_fdt_info(scsi_qla_host_t *vha)
|
||||
{
|
||||
#define FLASH_BLK_SIZE_4K 0x1000
|
||||
#define FLASH_BLK_SIZE_32K 0x8000
|
||||
#define FLASH_BLK_SIZE_64K 0x10000
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct req_que *req = ha->req_q_map[0];
|
||||
uint16_t cnt, chksum;
|
||||
__le16 *wptr = (__force __le16 *)req->ring;
|
||||
struct qla_fdt_layout *fdt = (struct qla_fdt_layout *)req->ring;
|
||||
uint32_t fdt_options = 0;
|
||||
void *buf = NULL;
|
||||
|
||||
buf = qla29xx_read_optrom_data(vha, FLT_REG_FDT, fdt_options,
|
||||
fdt, 0, sizeof(*fdt));
|
||||
if (!buf) {
|
||||
ql_log(ql_log_warn, vha, 0x0047,
|
||||
"Failed to read FLT information.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(*wptr) == 0xffff)
|
||||
return;
|
||||
if (memcmp(fdt->sig, "QLID", 4))
|
||||
return;
|
||||
|
||||
for (cnt = 0, chksum = 0; cnt < sizeof(*fdt) >> 1; cnt++, wptr++)
|
||||
chksum += le16_to_cpu(*wptr);
|
||||
if (chksum) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x004c,
|
||||
"Inconsistent FDT detected: checksum=0x%x id=%c version0x%x.\n",
|
||||
chksum, fdt->sig[0], le16_to_cpu(fdt->version));
|
||||
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113,
|
||||
fdt, sizeof(*fdt));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_get_flash_region - Retrieve flash region information for QLA29xx adapters.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
* @code: Region code to identify the flash region.
|
||||
* @region: Pointer to store the retrieved flash region information.
|
||||
*
|
||||
* This function retrieves the flash region information for QLA29xx adapters
|
||||
* based on the specified region code.
|
||||
*
|
||||
* Returns QLA_SUCCESS on success or QLA_FUNCTION_FAILED on failure.
|
||||
*/
|
||||
static int
|
||||
qla29xx_get_flash_region(struct scsi_qla_host *vha, uint32_t code,
|
||||
struct qla_flt_region_data *region)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flash_layout *flt = ha->flt_data;
|
||||
struct qla_flt_region_header *flt_hdr = &flt->flt_header;
|
||||
struct qla_flt_region_data *flt_reg = &flt->region[0];
|
||||
uint16_t cnt;
|
||||
int rval = QLA_FUNCTION_FAILED;
|
||||
|
||||
if (!ha->flt_data || !ha->flags.valid_flt)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
cnt = le16_to_cpu(flt_hdr->region_count);
|
||||
if (cnt > FLT_MAX_REGIONS)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
/*
|
||||
* flt_reg++ strides by sizeof(struct qla_flt_region_data). This is
|
||||
* safe because valid_flt is set only after qla29xx_get_flt_layout()
|
||||
* has verified the firmware region_size equals that struct size.
|
||||
*/
|
||||
for (; cnt; cnt--, flt_reg++) {
|
||||
if (le16_to_cpu(flt_reg->region_code) == code) {
|
||||
memcpy((uint8_t *)region, flt_reg,
|
||||
sizeof(struct qla_flt_region_data));
|
||||
rval = QLA_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* set_segment_bits - Set segment-related bits in the options field.
|
||||
* @options: Pointer to the options field.
|
||||
* @segment_index: Index of the current segment.
|
||||
* @total: Total number of segments.
|
||||
*
|
||||
* This function sets the appropriate bits in the options field to indicate
|
||||
* whether the current segment is the first, last, or a single segment.
|
||||
*/
|
||||
static void set_segment_bits(uint16_t *options, int segment_index, int total)
|
||||
{
|
||||
/* - Single segment complete image.
|
||||
* - 1st Segment of an image.
|
||||
* - Last segment of an image.
|
||||
*/
|
||||
if (total == 1)
|
||||
*options |= (1 << 10) | (1 << 11);
|
||||
else if (segment_index == 0)
|
||||
*options |= (1 << 10);
|
||||
else if (segment_index == total - 1)
|
||||
*options |= (1 << 11);
|
||||
}
|
||||
|
||||
/**
|
||||
* set_chunk_bits - Set chunk-related bits in the options field.
|
||||
* @options: Pointer to the options field.
|
||||
* @count: Index of the current chunk.
|
||||
* @total: Total number of chunks.
|
||||
*
|
||||
* This function sets the appropriate bits in the options field to indicate
|
||||
* whether the current chunk is the first, last, or a single chunk.
|
||||
*/
|
||||
static void set_chunk_bits(uint16_t *options, int count, int total)
|
||||
{
|
||||
/* - Single chunk complete segment
|
||||
* - 1st chunk of a segment
|
||||
* - Last chunk of a segment
|
||||
*/
|
||||
if (total == 1)
|
||||
*options |= (1 << 4) | (1 << 5);
|
||||
else if (count == 0)
|
||||
*options |= (1 << 4);
|
||||
else if (count == total - 1)
|
||||
*options |= (1 << 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_write_optrom_data - Write data to the optrom for QLA29xx adapters.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
* @reg_code: Region code to write to.
|
||||
* @opts: Options for the write operation.
|
||||
* @buf: Buffer containing the data to write.
|
||||
* @offset: Offset within the region to start writing.
|
||||
* @length: Length of data to write.
|
||||
*
|
||||
* This function writes data to the specified optrom region for QLA29xx adapters.
|
||||
*
|
||||
* Returns 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int
|
||||
qla29xx_write_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
|
||||
uint16_t opts, void *buf, uint32_t offset,
|
||||
uint32_t length)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flt_region_data region;
|
||||
dma_addr_t optrom_dma;
|
||||
uint32_t faddr, left, burst;
|
||||
uint32_t img_len, seg_dlen;
|
||||
uint32_t region_len, region_dlen;
|
||||
void *optrom;
|
||||
uint8_t *pbuf;
|
||||
int rval = -EINVAL;
|
||||
uint16_t total_segments, segment_index = 0;
|
||||
uint16_t chunk_index = 0;
|
||||
|
||||
memset(®ion, 0, sizeof(region));
|
||||
|
||||
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
|
||||
&optrom_dma, GFP_KERNEL);
|
||||
if (!optrom) {
|
||||
ql_log(ql_log_warn, vha, 0x0090,
|
||||
"Unable to allocate memory for optrom burst read (%x KB).\n",
|
||||
OPTROM_BURST_SIZE / 1024);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ha->flags.valid_flt && length == 0) {
|
||||
/* Get image length and segment length from FLT */
|
||||
rval = qla29xx_get_flash_region(vha, reg_code, ®ion);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x0092,
|
||||
"Invalid address %x - not a region start address\n",
|
||||
reg_code);
|
||||
goto free_buf;
|
||||
}
|
||||
img_len = le32_to_cpu(region.image_length);
|
||||
} else {
|
||||
img_len = length;
|
||||
}
|
||||
|
||||
seg_dlen = ha->flt_segment_length >> 2;
|
||||
region_len = (length > 0) ? length : img_len;
|
||||
region_dlen = (region_len >> 2);
|
||||
total_segments = (region_dlen + seg_dlen - 1) / seg_dlen;
|
||||
|
||||
faddr = offset >> 2;
|
||||
left = region_dlen;
|
||||
burst = OPTROM_BURST_DWORDS;
|
||||
pbuf = buf;
|
||||
|
||||
while (region_dlen > 0) {
|
||||
uint32_t segment_size, total_chunks;
|
||||
uint16_t options = 0;
|
||||
|
||||
segment_size = (region_dlen > seg_dlen) ? seg_dlen : region_dlen;
|
||||
total_chunks = (segment_size + OPTROM_BURST_DWORDS - 1) /
|
||||
OPTROM_BURST_DWORDS;
|
||||
|
||||
burst = OPTROM_BURST_DWORDS;
|
||||
if (burst > left)
|
||||
burst = left;
|
||||
if (burst > segment_size - chunk_index * OPTROM_BURST_DWORDS)
|
||||
burst = segment_size - chunk_index * OPTROM_BURST_DWORDS;
|
||||
|
||||
set_segment_bits(&options, segment_index, total_segments);
|
||||
set_chunk_bits(&options, chunk_index, total_chunks);
|
||||
|
||||
/* flash block write operations */
|
||||
SET_FW_BIT(options, BIT_6);
|
||||
CLEAR_FW_BIT(options, BIT_9);
|
||||
|
||||
check_and_set_mbc_bits(opts, options, BIT_15, BIT_15);
|
||||
check_and_set_mbc_bits(opts, options, BIT_7, BIT_7);
|
||||
|
||||
if (segment_index == total_segments - 1 &&
|
||||
chunk_index == total_chunks - 1)
|
||||
check_and_set_mbc_bits(opts, options, BIT_8, BIT_8);
|
||||
|
||||
memcpy(optrom, pbuf, burst * 4);
|
||||
|
||||
/* faddr is offset relative to region code */
|
||||
rval = qla29xx_flash_block_write(vha, optrom_dma,
|
||||
faddr, burst, reg_code, options);
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x0095,
|
||||
"Unable to burst-write optrom segment (%x/%x/%llx).\n",
|
||||
rval, faddr, (unsigned long long)optrom_dma);
|
||||
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
|
||||
optrom, optrom_dma);
|
||||
goto exit_write;
|
||||
}
|
||||
|
||||
left -= burst;
|
||||
faddr += burst;
|
||||
pbuf += burst * 4;
|
||||
chunk_index++;
|
||||
if (chunk_index >= total_chunks) {
|
||||
chunk_index = 0;
|
||||
segment_index++;
|
||||
region_dlen -= segment_size;
|
||||
}
|
||||
}
|
||||
|
||||
free_buf:
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
|
||||
optrom_dma);
|
||||
return rval;
|
||||
|
||||
exit_write:
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_read_optrom_data - Read data from the optrom for QLA29xx adapters.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
* @reg_code: Region code to read from.
|
||||
* @opts: Options for the read operation.
|
||||
* @buf: Buffer to store the read data.
|
||||
* @offset: Offset within the region to start reading.
|
||||
* @length: Length of data to read.
|
||||
*
|
||||
* This function reads data from the specified optrom region for QLA29xx adapters.
|
||||
*
|
||||
* Returns a pointer to the buffer on success or NULL on failure.
|
||||
*/
|
||||
void *
|
||||
qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
|
||||
uint16_t opts, void *buf, uint32_t offset,
|
||||
uint32_t length)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flt_region_data region;
|
||||
dma_addr_t optrom_dma;
|
||||
uint32_t faddr, left, burst;
|
||||
uint32_t img_len, seg_dlen;
|
||||
uint32_t region_len, region_dlen;
|
||||
void *optrom;
|
||||
uint8_t *pbuf;
|
||||
uint16_t total_segments, segment_index = 0;
|
||||
uint16_t chunk_index = 0;
|
||||
int rval;
|
||||
|
||||
memset(®ion, 0, sizeof(region));
|
||||
|
||||
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
|
||||
&optrom_dma, GFP_KERNEL);
|
||||
if (!optrom) {
|
||||
ql_log(ql_log_warn, vha, 0x0093,
|
||||
"Unable to allocate memory for optrom burst read (%x KB).\n",
|
||||
OPTROM_BURST_SIZE / 1024);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ha->flags.valid_flt && length == 0) {
|
||||
/* Get image length and segment length from FLT */
|
||||
rval = qla29xx_get_flash_region(vha, reg_code, ®ion);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x7033,
|
||||
"Invalid address %x - not a region start address\n",
|
||||
reg_code);
|
||||
goto free_buf;
|
||||
}
|
||||
img_len = le32_to_cpu(region.image_length);
|
||||
} else {
|
||||
img_len = length;
|
||||
}
|
||||
|
||||
seg_dlen = ha->flt_segment_length >> 2;
|
||||
region_len = (length > 0) ? length : img_len;
|
||||
region_dlen = (region_len >> 2);
|
||||
total_segments = (region_dlen + seg_dlen - 1) / seg_dlen;
|
||||
|
||||
faddr = offset >> 2;
|
||||
left = region_dlen;
|
||||
burst = OPTROM_BURST_DWORDS;
|
||||
pbuf = buf;
|
||||
|
||||
ql_log(ql_log_info, vha, 0x0096,
|
||||
"Reg[0x%x]: options=0x%x length=0x%x offset=0x%x segments=%u\n",
|
||||
reg_code, opts, region_len, offset, total_segments);
|
||||
|
||||
while (region_dlen > 0) {
|
||||
uint32_t segment_size, total_chunks;
|
||||
uint16_t options = 0;
|
||||
|
||||
segment_size = (region_dlen > seg_dlen) ? seg_dlen : region_dlen;
|
||||
total_chunks = (segment_size + OPTROM_BURST_DWORDS - 1) /
|
||||
OPTROM_BURST_DWORDS;
|
||||
|
||||
burst = OPTROM_BURST_DWORDS;
|
||||
if (burst > left)
|
||||
burst = left;
|
||||
if (burst > segment_size - chunk_index * OPTROM_BURST_DWORDS)
|
||||
burst = segment_size - chunk_index * OPTROM_BURST_DWORDS;
|
||||
|
||||
set_segment_bits(&options, segment_index, total_segments);
|
||||
set_chunk_bits(&options, chunk_index, total_chunks);
|
||||
|
||||
/* flash block read operations */
|
||||
CLEAR_FW_BIT(options, BIT_9);
|
||||
CLEAR_FW_BIT(options, BIT_6);
|
||||
|
||||
options |= opts;
|
||||
|
||||
/* faddr is offset relative to region code */
|
||||
rval = qla29xx_flash_block_read(vha, optrom_dma,
|
||||
faddr, burst, reg_code, options);
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x0097,
|
||||
"Unable to burst-read optrom segment (%x/%x/%llx).\n",
|
||||
rval, faddr, (unsigned long long)optrom_dma);
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
memcpy(pbuf, optrom, burst * 4);
|
||||
|
||||
left -= burst;
|
||||
faddr += burst;
|
||||
pbuf += burst * 4;
|
||||
chunk_index++;
|
||||
if (chunk_index >= total_chunks) {
|
||||
chunk_index = 0;
|
||||
segment_index++;
|
||||
region_dlen -= segment_size;
|
||||
}
|
||||
}
|
||||
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
|
||||
optrom_dma);
|
||||
return buf;
|
||||
|
||||
free_buf:
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
|
||||
optrom_dma);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void set_chunk_mpi_bits(uint16_t *options, int count, int total)
|
||||
{
|
||||
/* - Single chunk complete segment/image
|
||||
* - 1st chunk of a segment/image
|
||||
* - Last chunk of a segment/image
|
||||
*/
|
||||
if (total == 1)
|
||||
*options |= BIT_2 | BIT_1;
|
||||
else if (count == 0)
|
||||
*options |= BIT_1;
|
||||
else if (count == total - 1)
|
||||
*options |= BIT_2;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_mpi_optrom_data - Dump/load MPI optrom data for 29xx.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
* @opts: Options for the operation.
|
||||
* @buf: Buffer to read from/write to.
|
||||
* @offset: Offset into the device memory.
|
||||
* @length: Length of data, in bytes.
|
||||
* @op: Operation, either QLA29XX_MPI_OP_DUMP or QLA29XX_MPI_OP_LOAD.
|
||||
*
|
||||
* Returns:
|
||||
* QLA_SUCCESS on success or an error code on failure.
|
||||
*/
|
||||
int
|
||||
qla29xx_mpi_optrom_data(struct scsi_qla_host *vha, uint16_t opts, void *buf,
|
||||
uint32_t offset, uint32_t length, enum qla29xx_mpi_optrom_op op)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
dma_addr_t optrom_dma;
|
||||
void *optrom;
|
||||
uint32_t mpi_addr, mpi_size, burst = 0;
|
||||
uint32_t total_chunks = 0;
|
||||
uint32_t *dcode, *fwcode;
|
||||
uint32_t chunk_count = 0;
|
||||
int rval = -EINVAL;
|
||||
|
||||
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
|
||||
&optrom_dma, GFP_KERNEL);
|
||||
if (!optrom) {
|
||||
ql_log(ql_log_warn, vha, 0x0090,
|
||||
"Unable to allocate memory for optrom burst read (%x KB).\n",
|
||||
OPTROM_BURST_SIZE / 1024);
|
||||
rval = -ENOMEM;
|
||||
goto exit_mpi_op;
|
||||
}
|
||||
|
||||
mpi_addr = offset;
|
||||
dcode = (uint32_t *)optrom;
|
||||
memset(dcode, 0, OPTROM_BURST_SIZE);
|
||||
|
||||
fwcode = (uint32_t *)buf;
|
||||
mpi_size = length >> 2;
|
||||
burst = OPTROM_BURST_SIZE >> 2;
|
||||
total_chunks = (mpi_size + burst - 1) / burst;
|
||||
|
||||
while (mpi_size > 0) {
|
||||
uint16_t options = 0;
|
||||
|
||||
if (burst > mpi_size)
|
||||
burst = mpi_size;
|
||||
|
||||
set_chunk_mpi_bits(&options, chunk_count, total_chunks);
|
||||
|
||||
if (op == QLA29XX_MPI_OP_DUMP) {
|
||||
options |= (BIT_0);
|
||||
options |= opts;
|
||||
|
||||
ql_log(ql_log_info, vha, 0x008b,
|
||||
"-> %s (DUMP): %#x <-(%#x words) (0x%x options) chunk (0x%x, 0x%x)\n",
|
||||
__func__, mpi_addr, burst, options, chunk_count,
|
||||
total_chunks);
|
||||
|
||||
memcpy(dcode, fwcode, burst * 4);
|
||||
|
||||
rval = qla29xx_load_dump_mpi(vha, options, mpi_addr, burst,
|
||||
optrom_dma);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"Failed dump mpi firmware.\n");
|
||||
goto free_buf;
|
||||
}
|
||||
} else if (op == QLA29XX_MPI_OP_LOAD) {
|
||||
options |= opts;
|
||||
|
||||
ql_log(ql_log_info, vha, 0x008b,
|
||||
"-> %s (LOAD): %#x <-(%#x words) (0x%x options) chunk (0x%x, 0x%x)\n",
|
||||
__func__, mpi_addr, burst, options, chunk_count,
|
||||
total_chunks);
|
||||
|
||||
rval = qla29xx_load_dump_mpi(vha, options, mpi_addr, burst,
|
||||
optrom_dma);
|
||||
if (rval) {
|
||||
ql_log(ql_log_fatal, vha, 0x0098,
|
||||
"Failed load mpi firmware.\n");
|
||||
goto free_buf;
|
||||
}
|
||||
memcpy(fwcode, dcode, burst * 4);
|
||||
}
|
||||
|
||||
chunk_count++;
|
||||
fwcode += burst;
|
||||
mpi_addr += burst;
|
||||
mpi_size -= burst;
|
||||
}
|
||||
|
||||
rval = QLA_SUCCESS;
|
||||
free_buf:
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
|
||||
optrom_dma);
|
||||
|
||||
exit_mpi_op:
|
||||
return rval;
|
||||
}
|
||||
|
||||
/*
|
||||
* NVRAM support routines
|
||||
*/
|
||||
@@ -1117,10 +1765,18 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
|
||||
uint32_t flt_addr;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
|
||||
!IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
return QLA_SUCCESS;
|
||||
if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) && !IS_CNA_CAPABLE(ha) &&
|
||||
!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha) &&
|
||||
!IS_QLA29XX(ha))
|
||||
goto done;
|
||||
|
||||
if (IS_QLA29XX(ha)) {
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
qla29xx_get_flt_layout(vha);
|
||||
qla29xx_get_fdt_info(vha);
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (IS_QLA28XX(ha) && !qla28xx_validate_mcu_signature(vha))
|
||||
ha->flags.secure_mcu = 1;
|
||||
@@ -1132,7 +1788,7 @@ qla2xxx_get_flash_info(scsi_qla_host_t *vha)
|
||||
qla2xxx_get_flt_info(vha, flt_addr);
|
||||
qla2xxx_get_fdt_info(vha);
|
||||
qla2xxx_get_idc_param(vha);
|
||||
|
||||
done:
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1374,7 +2030,7 @@ qla24xx_write_flash_data(scsi_qla_host_t *vha, __le32 *dwptr, uint32_t faddr,
|
||||
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
|
||||
"Write burst (%#lx dwords)...\n", dburst);
|
||||
ret = qla2x00_load_ram(vha, optrom_dma,
|
||||
flash_data_addr(ha, faddr), dburst);
|
||||
flash_data_addr(ha, faddr), dburst, 0);
|
||||
if (!ret) {
|
||||
liter += dburst - 1;
|
||||
faddr += dburst - 1;
|
||||
@@ -2974,7 +3630,7 @@ qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
|
||||
ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
|
||||
"Write burst (%#lx dwords)...\n", dburst);
|
||||
rval = qla2x00_load_ram(vha, optrom_dma,
|
||||
flash_data_addr(ha, faddr), dburst);
|
||||
flash_data_addr(ha, faddr), dburst, 0);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x7097,
|
||||
"Failed burst write at %x (%p/%#llx)...\n",
|
||||
@@ -3448,6 +4104,86 @@ qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the boot BIOS/FCODE/EFI version for 29xx adapters.
|
||||
*
|
||||
* 29xx reads flash through an FLT region code plus a region-relative
|
||||
* offset. The firmware only honours such a read at the region base
|
||||
* (offset 0) and rejects a non-zero offset with MBS_COMMAND_ERROR. The
|
||||
* PCI expansion ROM header and the PCI data structure it points to both
|
||||
* live within the first dwords of FLT_REG_BOOT_CODE, so read one bounded
|
||||
* block at offset 0 and parse both structures from memory instead of
|
||||
* issuing a second read at the PCI-data-structure offset.
|
||||
*/
|
||||
#define QLA29XX_BOOT_PROBE_LEN 0x100
|
||||
|
||||
static void
|
||||
qla29xx_get_boot_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint8_t *bcode = mbuf;
|
||||
uint32_t pcids;
|
||||
uint8_t code_type;
|
||||
|
||||
if (!qla29xx_read_optrom_data(vha, FLT_REG_BOOT_CODE, 0, mbuf, 0,
|
||||
QLA29XX_BOOT_PROBE_LEN)) {
|
||||
ql_log(ql_log_info, vha, 0x018e,
|
||||
"Unable to read PCI Data Structure.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify PCI expansion ROM header. */
|
||||
if (memcmp(bcode, "\x55\xaa", 2)) {
|
||||
ql_log(ql_log_info, vha, 0x0059,
|
||||
"No matching ROM signature.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Locate the PCI data structure within the buffer. */
|
||||
pcids = (bcode[0x19] << 8) | bcode[0x18];
|
||||
if (pcids + 0x16 > QLA29XX_BOOT_PROBE_LEN)
|
||||
return;
|
||||
|
||||
bcode += pcids;
|
||||
|
||||
/* Validate signature of PCI data structure. */
|
||||
if (memcmp(bcode, "PCIR", 4)) {
|
||||
ql_log(ql_log_info, vha, 0x005a,
|
||||
"PCI data struct not found pcir_adr=%x.\n", pcids);
|
||||
return;
|
||||
}
|
||||
|
||||
code_type = bcode[0x14];
|
||||
switch (code_type) {
|
||||
case ROM_CODE_TYPE_BIOS:
|
||||
/* Intel x86, PC-AT compatible. */
|
||||
ha->bios_revision[0] = bcode[0x12];
|
||||
ha->bios_revision[1] = bcode[0x13];
|
||||
ql_dbg(ql_dbg_init, vha, 0x005b, "Read BIOS %d.%d.\n",
|
||||
ha->bios_revision[1], ha->bios_revision[0]);
|
||||
break;
|
||||
case ROM_CODE_TYPE_FCODE:
|
||||
/* Open Firmware standard for PCI (FCode). */
|
||||
ha->fcode_revision[0] = bcode[0x12];
|
||||
ha->fcode_revision[1] = bcode[0x13];
|
||||
ql_dbg(ql_dbg_init, vha, 0x005c, "Read FCODE %d.%d.\n",
|
||||
ha->fcode_revision[1], ha->fcode_revision[0]);
|
||||
break;
|
||||
case ROM_CODE_TYPE_EFI:
|
||||
/* Extensible Firmware Interface (EFI). */
|
||||
ha->efi_revision[0] = bcode[0x12];
|
||||
ha->efi_revision[1] = bcode[0x13];
|
||||
ql_dbg(ql_dbg_init, vha, 0x005d, "Read EFI %d.%d.\n",
|
||||
ha->efi_revision[1], ha->efi_revision[0]);
|
||||
break;
|
||||
default:
|
||||
ql_log(ql_log_warn, vha, 0x005e,
|
||||
"Unrecognized code type %x at pcids %x.\n",
|
||||
code_type, pcids);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
{
|
||||
@@ -3472,12 +4208,31 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
|
||||
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
|
||||
|
||||
/* ISP29xx: get FW version from FLT region metadata */
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct qla_flt_region_data region;
|
||||
|
||||
ret = qla29xx_get_flash_region(vha, FLT_REG_FW, ®ion);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x7033,
|
||||
"Invalid region %x\n", FLT_REG_FW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ha->fw_revision[0] = (le32_to_cpu(region.version) >> 16) & 0xff;
|
||||
ha->fw_revision[1] = (le32_to_cpu(region.version) >> 8) & 0xff;
|
||||
ha->fw_revision[2] = le32_to_cpu(region.version) & 0xff;
|
||||
|
||||
/* BIOS/FCODE/EFI version from the boot-code region. */
|
||||
qla29xx_get_boot_version(vha, mbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pcihdr = ha->flt_region_boot << 2;
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
qla27xx_get_active_image(vha, &active_regions);
|
||||
if (active_regions.global == QLA27XX_SECONDARY_IMAGE) {
|
||||
if (active_regions.global == QLA27XX_SECONDARY_IMAGE)
|
||||
pcihdr = ha->flt_region_boot_sec << 2;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -3486,7 +4241,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
if (ret) {
|
||||
ql_log(ql_log_info, vha, 0x017d,
|
||||
"Unable to read PCI EXP Rom Header(%x).\n", ret);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
bcode = mbuf + (pcihdr % 4);
|
||||
@@ -3494,7 +4249,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
/* No signature */
|
||||
ql_log(ql_log_fatal, vha, 0x0059,
|
||||
"No matching ROM signature.\n");
|
||||
return QLA_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Locate PCI data structure. */
|
||||
@@ -3504,7 +4259,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
if (ret) {
|
||||
ql_log(ql_log_info, vha, 0x018e,
|
||||
"Unable to read PCI Data Structure (%x).\n", ret);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
bcode = mbuf + (pcihdr % 4);
|
||||
@@ -3515,7 +4270,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
ql_log(ql_log_fatal, vha, 0x005a,
|
||||
"PCI data struct not found pcir_adr=%x.\n", pcids);
|
||||
ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read version */
|
||||
|
||||
@@ -1738,8 +1738,8 @@ static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr;
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp = (struct abts_resp_to_24xx *)qla_req_ring_slot(ha, qpair->req);
|
||||
memset(resp, 0, qla_req_entry_size(ha));
|
||||
|
||||
h = qlt_make_handle(qpair);
|
||||
if (unlikely(h == QLA_TGT_NULL_HANDLE)) {
|
||||
@@ -2490,17 +2490,13 @@ static int qlt_check_reserve_free_req(struct qla_qpair *qpair,
|
||||
/*
|
||||
* ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
|
||||
*/
|
||||
static inline void *qlt_get_req_pkt(struct req_que *req)
|
||||
static inline void *qlt_get_req_pkt(struct qla_hw_data *ha,
|
||||
struct req_que *req)
|
||||
{
|
||||
/* Adjust ring index. */
|
||||
req->ring_index++;
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ptr = req->ring;
|
||||
} else {
|
||||
req->ring_ptr++;
|
||||
}
|
||||
return (cont_entry_t *)req->ring_ptr;
|
||||
qla_req_ring_advance(ha, req);
|
||||
|
||||
return qla_req_ring_slot(ha, req);
|
||||
}
|
||||
|
||||
/* ha->hardware_lock supposed to be held on entry */
|
||||
@@ -2549,9 +2545,9 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair,
|
||||
uint16_t temp;
|
||||
struct qla_tgt_cmd *cmd = prm->cmd;
|
||||
|
||||
pkt = (struct ctio7_to_24xx *)qpair->req->ring_ptr;
|
||||
pkt = (struct ctio7_to_24xx *)qla_req_ring_slot(qpair->hw, qpair->req);
|
||||
prm->pkt = pkt;
|
||||
memset(pkt, 0, sizeof(*pkt));
|
||||
memset(pkt, 0, qla_req_entry_size(qpair->hw));
|
||||
|
||||
pkt->entry_type = CTIO_TYPE7;
|
||||
pkt->entry_count = (uint8_t)prm->req_cnt;
|
||||
@@ -2600,11 +2596,12 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
|
||||
{
|
||||
int cnt;
|
||||
struct dsd64 *cur_dsd;
|
||||
struct qla_hw_data *ha = prm->cmd->qpair->hw;
|
||||
|
||||
/* Build continuation packets */
|
||||
while (prm->seg_cnt > 0) {
|
||||
cont_a64_entry_t *cont_pkt64 =
|
||||
(cont_a64_entry_t *)qlt_get_req_pkt(
|
||||
(cont_a64_entry_t *)qlt_get_req_pkt(ha,
|
||||
prm->cmd->qpair->req);
|
||||
|
||||
/*
|
||||
@@ -2614,7 +2611,7 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
|
||||
* that.
|
||||
*/
|
||||
|
||||
memset(cont_pkt64, 0, sizeof(*cont_pkt64));
|
||||
memset(cont_pkt64, 0, qla_req_entry_size(ha));
|
||||
|
||||
cont_pkt64->entry_count = 1;
|
||||
cont_pkt64->sys_define = 0;
|
||||
@@ -3012,9 +3009,9 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm)
|
||||
|
||||
ha = vha->hw;
|
||||
|
||||
pkt = (struct ctio_crc2_to_fw *)qpair->req->ring_ptr;
|
||||
pkt = (struct ctio_crc2_to_fw *)qla_req_ring_slot(ha, qpair->req);
|
||||
prm->pkt = pkt;
|
||||
memset(pkt, 0, sizeof(*pkt));
|
||||
memset(pkt, 0, qla_req_entry_size(ha));
|
||||
|
||||
ql_dbg_qp(ql_dbg_tgt, cmd->qpair, 0xe071,
|
||||
"qla_target(%d):%s: se_cmd[%p] CRC2 prot_op[0x%x] cmd prot sg:cnt[%p:%x] lba[%llu]\n",
|
||||
@@ -3306,7 +3303,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
|
||||
*/
|
||||
struct ctio7_to_24xx *ctio =
|
||||
(struct ctio7_to_24xx *)qlt_get_req_pkt(
|
||||
qpair->req);
|
||||
vha->hw, qpair->req);
|
||||
|
||||
ql_dbg_qp(ql_dbg_tgt, qpair, 0x305e,
|
||||
"Building additional status packet 0x%p.\n",
|
||||
@@ -3316,6 +3313,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
|
||||
* T10Dif: ctio_crc2_to_fw overlay ontop of
|
||||
* ctio7_to_24xx
|
||||
*/
|
||||
memset(ctio, 0, qla_req_entry_size(vha->hw));
|
||||
memcpy(ctio, pkt, sizeof(*ctio));
|
||||
/* reset back to CTIO7 */
|
||||
ctio->entry_count = 1;
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
/*
|
||||
* Driver version
|
||||
*/
|
||||
#define QLA2XXX_VERSION "10.02.10.100-k"
|
||||
#define QLA2XXX_VERSION "12.00.00.2607b1"
|
||||
|
||||
#define QLA_DRIVER_MAJOR_VER 10
|
||||
#define QLA_DRIVER_MINOR_VER 02
|
||||
#define QLA_DRIVER_PATCH_VER 10
|
||||
#define QLA_DRIVER_BETA_VER 100
|
||||
#define QLA_DRIVER_MAJOR_VER 12
|
||||
#define QLA_DRIVER_MINOR_VER 00
|
||||
#define QLA_DRIVER_PATCH_VER 00
|
||||
#define QLA_DRIVER_BETA_VER 2607
|
||||
|
||||
Reference in New Issue
Block a user