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:
Martin K. Petersen (Oracle)
2026-08-07 10:31:07 -04:00
24 changed files with 6097 additions and 1047 deletions

View File

@@ -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)

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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)

View File

@@ -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,

View File

@@ -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

View 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

View File

@@ -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);

View File

@@ -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;
}

View File

@@ -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(&reg->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. */

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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 = &reg->isp25mq.req_q_in;
req->req_q_out = &reg->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 = &reg->isp25mq.rsp_q_in;
rsp->rsp_q_out = &reg->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)

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 "

View File

@@ -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);

View File

@@ -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(&region, 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, &region);
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(&region, 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, &region);
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, &region);
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 */

View File

@@ -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;

View File

@@ -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