mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley: "One new driver: leapraid (similar to mpi3mr but OK'd by Broadcom). The usual suspects for driver updates (ufs, qla2xxx, smartpqi, zfcp, fnic, ibmvfc) plus a few small core updates: a fix for an uninitialized sg list pad bytes plus the removal of the dma mask check for max sectors. The big update in the sd driver is mostly code refactoring for obscure error leg handling" * tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (195 commits) scsi: fnic: Fix built-in NVMe/FC build scsi: fnic: Fix invalid comparison for error scsi: core: Fill in DMA padding bytes in scsi_alloc_sgtables() scsi: zfcp: Enable CONTEXT_ANALYSIS scsi: zfcp: Add __must_hold() attribute to zfcp_qdio_sbal_get() scsi: fnic: Use GFP_ATOMIC for VLAN alloc under spinlock scsi: storvsc: Support manual scans for all Hyper-V targets scsi: sd: Fix sd_done() sense handling condition scsi: sd: Fix special_vec mempool leak when scsi_alloc_sgtables() fails scsi: sd: Fix error handling in sd_probe() after large pool creation failure scsi: leapraid: Add driver documentation scsi: leapraid: Add new SCSI driver scsi: ufs: Add support for the aggregated read query opcode scsi: ufs: Use unsigned types for the BSG query scsi: ibmvfc: Fix spelling mistake "Deleteing" -> "Deleting" scsi: qla2xxx: Update version to 12.00.00.2607b2 scsi: qla2xxx: Bound i2c->length in I2C bsg handlers scsi: qla2xxx: Zero SFP DMA buffer in FRU/I2C bsg handlers scsi: qla2xxx: Validate BSG request_len before reading vendor_cmd[] scsi: qla2xxx: Zero-init bsg stack buffers to avoid info leak ...
This commit is contained in:
@@ -18,6 +18,7 @@ select:
|
||||
- qcom,eliza-ufshc
|
||||
- qcom,hawi-ufshc
|
||||
- qcom,kaanapali-ufshc
|
||||
- qcom,maili-ufshc
|
||||
- qcom,nord-ufshc
|
||||
- qcom,sm8650-ufshc
|
||||
- qcom,sm8750-ufshc
|
||||
@@ -31,6 +32,7 @@ properties:
|
||||
- qcom,eliza-ufshc
|
||||
- qcom,hawi-ufshc
|
||||
- qcom,kaanapali-ufshc
|
||||
- qcom,maili-ufshc
|
||||
- qcom,nord-ufshc
|
||||
- qcom,sm8650-ufshc
|
||||
- qcom,sm8750-ufshc
|
||||
@@ -78,6 +80,7 @@ allOf:
|
||||
contains:
|
||||
enum:
|
||||
- qcom,eliza-ufshc
|
||||
- qcom,maili-ufshc
|
||||
- qcom,nord-ufshc
|
||||
then:
|
||||
properties:
|
||||
|
||||
@@ -105,6 +105,64 @@ properties:
|
||||
Restricts the UFS controller to rate-a or rate-b for both TX and
|
||||
RX directions.
|
||||
|
||||
tx-precode-enable-g6:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
minItems: 1
|
||||
items:
|
||||
- items:
|
||||
- description: Host_Lane0 precode
|
||||
enum: [0, 1]
|
||||
- description: Device_Lane0 precode
|
||||
enum: [0, 1]
|
||||
- items:
|
||||
- description: Host_Lane1 precode
|
||||
enum: [0, 1]
|
||||
- description: Device_Lane1 precode
|
||||
enum: [0, 1]
|
||||
description:
|
||||
Static TX Precode enable values for HS-G6 only.
|
||||
|
||||
patternProperties:
|
||||
"^txeq-preshoot-g[1-6]$":
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
minItems: 1
|
||||
items:
|
||||
- items:
|
||||
- description: Host_Lane0 Preshoot value
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
- description: Device_Lane0 Preshoot value
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
- items:
|
||||
- description: Host_Lane1 Preshoot value
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
- description: Device_Lane1 Preshoot value
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
description: |
|
||||
Static TX Equalization PreShoot settings for High Speed Gears. These
|
||||
values are programmed to the corresponding UniPro PA layer attribute
|
||||
PA_TxEQG[1-6]Setting. Each value selects a Pre-Shoot level as defined
|
||||
by the MIPI M-PHY specification (TX_HS_PreShoot_Setting).
|
||||
|
||||
"^txeq-deemphasis-g[1-6]$":
|
||||
$ref: /schemas/types.yaml#/definitions/uint32-matrix
|
||||
minItems: 1
|
||||
items:
|
||||
- items:
|
||||
- description: Host_Lane0 DeEmphasis value
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
- description: Device_Lane0 DeEmphasis value
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
- items:
|
||||
- description: Host_Lane1 DeEmphasis value
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
- description: Device_Lane1 DeEmphasis value
|
||||
enum: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
description: |
|
||||
Static TX Equalization DeEmphasis settings for High Speed Gears. These
|
||||
values are programmed to the corresponding UniPro PA layer attribute
|
||||
PA_TxEQG[1-6]Setting. Each value selects a De-Emphasis level as defined
|
||||
by the MIPI M-PHY specification (TX_HS_DeEmphasis_Setting).
|
||||
|
||||
dependencies:
|
||||
freq-table-hz: [ clocks ]
|
||||
operating-points-v2: [ clocks, clock-names ]
|
||||
|
||||
@@ -56,6 +56,7 @@ SCSI host adapter drivers
|
||||
g_NCR5380
|
||||
hpsa
|
||||
hptiop
|
||||
leapraid
|
||||
libsas
|
||||
lpfc
|
||||
megaraid
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
=========================
|
||||
LeapRAID Driver for Linux
|
||||
=========================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
LeapRAID is a storage RAID controller driver developed by LeapIO Tech Inc. The
|
||||
controller targets enterprise storage, cloud infrastructure, high performance
|
||||
computing (HPC), and AI workloads.
|
||||
|
||||
It provides high-performance storage virtualization over PCI Express Gen4
|
||||
and supports both SAS and SATA HDDs and SSDs. It offers both Host Bus Adapter
|
||||
and RAID modes to meet diverse deployment requirements.
|
||||
|
||||
Supported devices
|
||||
=================
|
||||
|
||||
- LeapHBA-8200C
|
||||
|
||||
Features
|
||||
========
|
||||
- PCIe Gen4 x8 host interface
|
||||
- Support for SAS and SATA devices
|
||||
- RAID levels: 0, 1, 10, 5, 50, 6, 60
|
||||
- Advanced error handling and end-to-end data integrity
|
||||
|
||||
LeapRAID specific host attributes
|
||||
=================================
|
||||
|
||||
::
|
||||
|
||||
/sys/class/scsi_host/host*/fw_queue_depth
|
||||
/sys/class/scsi_host/host*/host_sas_address
|
||||
/sys/class/scsi_host/host*/board_name
|
||||
|
||||
The host "fw_queue_depth" read-only attribute shows the firmware queue
|
||||
depth of the host.
|
||||
|
||||
The host "host_sas_address" read-only attribute shows the SAS address
|
||||
of the host.
|
||||
|
||||
The host "board_name" read-only attribute shows the board name reported
|
||||
by manufacturing page 0.
|
||||
|
||||
LeapRAID specific disk attributes
|
||||
=================================
|
||||
|
||||
::
|
||||
|
||||
/sys/class/scsi_disk/host:bus:target:lun/device/sas_device_handle
|
||||
/sys/class/scsi_disk/host:bus:target:lun/device/ncq_cmd_prio_enable
|
||||
|
||||
The read-only attribute "sas_device_handle" represents the disk's device
|
||||
handle, which is a unique identifier maintained by the firmware.
|
||||
|
||||
This attribute "ncq_cmd_prio_enable" controls NCQ command priority. A value
|
||||
of 0 disables NCQ priority handling for RT-priority I/O. Writing 1 enables
|
||||
NCQ priority handling when the device reports support for the feature through
|
||||
VPD page 0x89. Unsupported devices keep the effective state at 0.
|
||||
|
||||
LeapRAID module parameters
|
||||
==========================
|
||||
|
||||
The following module parameters can be configured at driver load time to
|
||||
control driver behavior and tuning options.
|
||||
|
||||
1. open_pcie_trace
|
||||
------------------
|
||||
|
||||
This parameter controls whether PCIe transaction tracing is enabled in the
|
||||
driver. When set to 1, PCIe trace collection is enabled by default, allowing
|
||||
detailed tracing of PCIe operations for debugging and performance analysis.
|
||||
Setting it to 0 disables the trace functionality to reduce overhead in
|
||||
production environments.
|
||||
|
||||
2. enable_mp
|
||||
------------
|
||||
|
||||
This parameter enables or disables multipath support for target devices.
|
||||
When set to 1, multipath functionality is enabled (default), allowing
|
||||
multiple paths to be established. Setting it to 0 disables multipath
|
||||
handling.
|
||||
|
||||
3. max_msix_vectors
|
||||
-------------------
|
||||
|
||||
This parameter sets the upper limit on the number of MSI-X interrupt
|
||||
vectors that the driver will request during initialization. The default
|
||||
value of -1 allows the driver to use all available vectors as provided
|
||||
by the device. Setting a positive integer restricts the number of vectors.
|
||||
|
||||
4. poll_queues
|
||||
--------------
|
||||
|
||||
This parameter specifies the number of I/O queues to be used when operating
|
||||
in io_uring poll mode. The default value is 0.
|
||||
|
||||
File Location
|
||||
=============
|
||||
The driver source is located at:
|
||||
|
||||
``drivers/scsi/leapraid/``
|
||||
|
||||
.. note::
|
||||
|
||||
This document is intended for kernel developers and system
|
||||
integrators who need to build, test, and deploy the LeapRAID driver.
|
||||
+9
-3
@@ -11820,7 +11820,7 @@ F: Documentation/devicetree/bindings/infiniband/hisilicon-hns-roce.txt
|
||||
F: drivers/infiniband/hw/hns/
|
||||
|
||||
HISILICON SAS Controller
|
||||
M: Yihang Li <liyihang9@h-partners.com>
|
||||
M: Xingui Yang <yangxingui@huawei.com>
|
||||
S: Supported
|
||||
W: http://www.hisilicon.com
|
||||
F: Documentation/devicetree/bindings/scsi/hisilicon-sas.txt
|
||||
@@ -14689,6 +14689,13 @@ S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
|
||||
F: scripts/leaking_addresses.pl
|
||||
|
||||
LEAPIO SCSI RAID DRIVER
|
||||
M: Dongdong Hao <doubled@leap-io-kernel.com>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
S: Supported
|
||||
F: Documentation/scsi/leapraid.rst
|
||||
F: drivers/scsi/leapraid/
|
||||
|
||||
LED SUBSYSTEM
|
||||
M: Lee Jones <lee@kernel.org>
|
||||
M: Pavel Machek <pavel@kernel.org>
|
||||
@@ -24411,9 +24418,8 @@ F: include/uapi/scsi/
|
||||
F: include/ufs/
|
||||
|
||||
SCSI TAPE DRIVER
|
||||
M: Kai Mäkisara <Kai.Makisara@kolumbus.fi>
|
||||
L: linux-scsi@vger.kernel.org
|
||||
S: Maintained
|
||||
S: Orphan
|
||||
F: Documentation/scsi/st.rst
|
||||
F: drivers/scsi/st.*
|
||||
F: drivers/scsi/st_*.h
|
||||
|
||||
@@ -252,9 +252,9 @@ static void pata_buddha_remove(struct zorro_dev *z)
|
||||
}
|
||||
|
||||
static const struct zorro_device_id pata_buddha_zorro_tbl[] = {
|
||||
{ ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA, BOARD_BUDDHA},
|
||||
{ ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL, BOARD_CATWEASEL},
|
||||
{ 0 }
|
||||
{ .id = ZORRO_PROD_INDIVIDUAL_COMPUTERS_BUDDHA, .driver_data = BOARD_BUDDHA },
|
||||
{ .id = ZORRO_PROD_INDIVIDUAL_COMPUTERS_CATWEASEL, .driver_data = BOARD_CATWEASEL },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(zorro, pata_buddha_zorro_tbl);
|
||||
|
||||
@@ -281,7 +281,7 @@ static int __init pata_buddha_late_init(void)
|
||||
/* Manually bind to all X-Surf boards */
|
||||
while ((z = zorro_find_device(ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, z))) {
|
||||
static struct zorro_device_id xsurf_ent = {
|
||||
ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, BOARD_XSURF
|
||||
.id = ZORRO_PROD_INDIVIDUAL_COMPUTERS_X_SURF, .driver_data = BOARD_XSURF
|
||||
};
|
||||
|
||||
pata_buddha_probe(z, &xsurf_ent);
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
# Makefile for the S/390 specific device drivers
|
||||
#
|
||||
|
||||
CONTEXT_ANALYSIS := y
|
||||
|
||||
zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_dbf.o zfcp_erp.o \
|
||||
zfcp_fc.o zfcp_fsf.o zfcp_qdio.o zfcp_scsi.o zfcp_sysfs.o \
|
||||
zfcp_unit.o zfcp_diag.o
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Debug traces for zfcp.
|
||||
*
|
||||
* Copyright IBM Corp. 2002, 2023
|
||||
* Copyright IBM Corp. 2002, 2026
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "zfcp: " fmt
|
||||
@@ -35,13 +35,18 @@ static inline unsigned int zfcp_dbf_plen(unsigned int offset)
|
||||
return sizeof(struct zfcp_dbf_pay) + offset - ZFCP_DBF_PAY_MAX_REC;
|
||||
}
|
||||
|
||||
#define ZFCP_DBF_PAY_LEVEL 1
|
||||
|
||||
static inline
|
||||
void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area,
|
||||
u64 req_id)
|
||||
u64 req_id, int level)
|
||||
{
|
||||
struct zfcp_dbf_pay *pl = &dbf->pay_buf;
|
||||
u16 offset = 0, rec_length;
|
||||
|
||||
if (unlikely(!debug_level_enabled(dbf->pay, level)))
|
||||
return;
|
||||
|
||||
spin_lock(&dbf->pay_lock);
|
||||
memset(pl, 0, sizeof(*pl));
|
||||
pl->fsf_req_id = req_id;
|
||||
@@ -51,7 +56,7 @@ void zfcp_dbf_pl_write(struct zfcp_dbf *dbf, void *data, u16 length, char *area,
|
||||
rec_length = min((u16) ZFCP_DBF_PAY_MAX_REC,
|
||||
(u16) (length - offset));
|
||||
memcpy(pl->data, data + offset, rec_length);
|
||||
debug_event(dbf->pay, 1, pl, zfcp_dbf_plen(rec_length));
|
||||
debug_event(dbf->pay, level, pl, zfcp_dbf_plen(rec_length));
|
||||
|
||||
offset += rec_length;
|
||||
pl->counter++;
|
||||
@@ -96,7 +101,27 @@ void zfcp_dbf_hba_fsf_res(char *tag, int level, struct zfcp_fsf_req *req)
|
||||
|
||||
rec->pl_len = q_head->log_length;
|
||||
zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start,
|
||||
rec->pl_len, "fsf_res", req->req_id);
|
||||
rec->pl_len, "fsf_res", req->req_id,
|
||||
ZFCP_DBF_PAY_LEVEL);
|
||||
|
||||
if (q_head->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) {
|
||||
struct fsf_qtcb_bottom_support *q_bott =
|
||||
&req->qtcb->bottom.support;
|
||||
u32 plogi_len = 0, prli_len = 0;
|
||||
|
||||
if (q_bott->els1_length) {
|
||||
rec->u.res.plogi_len = q_bott->els1_length;
|
||||
plogi_len = min_t(u32, q_bott->els1_length,
|
||||
sizeof(q_bott->els));
|
||||
}
|
||||
if (q_bott->els2_length) {
|
||||
rec->u.res.prli_len = q_bott->els2_length;
|
||||
prli_len = min_t(u32, q_bott->els2_length,
|
||||
sizeof(q_bott->els) - plogi_len);
|
||||
}
|
||||
zfcp_dbf_pl_write(dbf, q_bott->els, plogi_len + prli_len,
|
||||
"fsf_els", req->req_id, 4);
|
||||
}
|
||||
|
||||
debug_event(dbf->hba, level, rec, sizeof(*rec));
|
||||
spin_unlock_irqrestore(&dbf->hba_lock, flags);
|
||||
@@ -220,6 +245,13 @@ void zfcp_dbf_hba_fsf_uss(char *tag, struct zfcp_fsf_req *req)
|
||||
rec->u.uss.lun = srb->fcp_lun;
|
||||
memcpy(&rec->u.uss.queue_designator, &srb->queue_designator,
|
||||
sizeof(rec->u.uss.queue_designator));
|
||||
rec->u.uss.length = srb->length;
|
||||
rec->u.uss.res1 = srb->res1;
|
||||
rec->u.uss.res2 = srb->res2;
|
||||
rec->u.uss.class = srb->class;
|
||||
rec->u.uss.res3 = srb->res3;
|
||||
rec->u.uss.s_id = ntoh24(srb->s_id);
|
||||
memcpy(&rec->u.uss.res4, &srb->res4, sizeof(rec->u.uss.res4));
|
||||
|
||||
/* status read buffer payload length */
|
||||
rec->pl_len = (!srb->length) ? 0 : srb->length -
|
||||
@@ -227,12 +259,48 @@ void zfcp_dbf_hba_fsf_uss(char *tag, struct zfcp_fsf_req *req)
|
||||
|
||||
if (rec->pl_len)
|
||||
zfcp_dbf_pl_write(dbf, srb->payload.data, rec->pl_len,
|
||||
"fsf_uss", req->req_id);
|
||||
"fsf_uss", req->req_id, ZFCP_DBF_PAY_LEVEL);
|
||||
log:
|
||||
debug_event(dbf->hba, level, rec, sizeof(*rec));
|
||||
spin_unlock_irqrestore(&dbf->hba_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_dbf_hba_uas - trace event for sysfs unit add store
|
||||
* @tag: tag indicating which kind of unit add store condition occurred
|
||||
* @level: debug trace level
|
||||
* @adapter: pointer to struct zfcp_adapter
|
||||
* @wwpn: remote port wwn
|
||||
* @fcp_lun: FCP LUN
|
||||
* @ret: return value
|
||||
*/
|
||||
void zfcp_dbf_hba_uas(char *tag, int level, struct zfcp_adapter *adapter,
|
||||
u64 wwpn, u64 fcp_lun, int ret)
|
||||
{
|
||||
struct zfcp_dbf *dbf = adapter->dbf;
|
||||
struct zfcp_dbf_hba *rec = &dbf->hba_buf;
|
||||
unsigned long flags;
|
||||
|
||||
if (unlikely(!debug_level_enabled(dbf->hba, level)))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&dbf->hba_lock, flags);
|
||||
memset(rec, 0, sizeof(*rec));
|
||||
|
||||
memcpy(rec->tag, tag, ZFCP_DBF_TAG_LEN);
|
||||
rec->id = ZFCP_DBF_HBA_UAS;
|
||||
rec->fsf_req_id = ~0u;
|
||||
rec->fsf_req_status = ~0u;
|
||||
rec->fsf_cmd = ~0u;
|
||||
rec->fsf_seq_no = ~0u;
|
||||
rec->u.uas.wwpn = wwpn;
|
||||
rec->u.uas.fcp_lun = fcp_lun;
|
||||
rec->u.uas.ret = ret;
|
||||
|
||||
debug_event(dbf->hba, level, rec, sizeof(*rec));
|
||||
spin_unlock_irqrestore(&dbf->hba_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* zfcp_dbf_hba_bit_err - trace event for bit error conditions
|
||||
* @tag: tag indicating which kind of bit error unsolicited status was received
|
||||
@@ -732,7 +800,7 @@ void zfcp_dbf_scsi_common(char *tag, int level, struct scsi_device *sdev,
|
||||
min_t(u16, max_t(u16, rec->pl_len,
|
||||
ZFCP_DBF_PAY_MAX_REC),
|
||||
FSF_FCP_RSP_SIZE),
|
||||
"fcp_riu", fsf->req_id);
|
||||
"fcp_riu", fsf->req_id, ZFCP_DBF_PAY_LEVEL);
|
||||
}
|
||||
|
||||
debug_event(dbf->scsi, level, rec, sizeof(*rec));
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* zfcp device driver
|
||||
* debug feature declarations
|
||||
*
|
||||
* Copyright IBM Corp. 2008, 2020
|
||||
* Copyright IBM Corp. 2008, 2026
|
||||
*/
|
||||
|
||||
#ifndef ZFCP_DBF_H
|
||||
@@ -140,6 +140,8 @@ struct zfcp_dbf_hba_res {
|
||||
u8 fsf_status_qual[FSF_STATUS_QUALIFIER_SIZE];
|
||||
u32 port_handle;
|
||||
u32 lun_handle;
|
||||
u32 plogi_len;
|
||||
u32 prli_len;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
@@ -149,6 +151,13 @@ struct zfcp_dbf_hba_res {
|
||||
* @d_id: destination ID
|
||||
* @lun: logical unit number
|
||||
* @queue_designator: queue designator
|
||||
* @length: buffer length
|
||||
* @res1: reserved field 1
|
||||
* @res2: reserved field 2
|
||||
* @class: class of service
|
||||
* @res3: reserved field 3
|
||||
* @s_id: source ID
|
||||
* @res4: reserved field 4
|
||||
*/
|
||||
struct zfcp_dbf_hba_uss {
|
||||
u32 status_type;
|
||||
@@ -156,6 +165,25 @@ struct zfcp_dbf_hba_uss {
|
||||
u32 d_id;
|
||||
u64 lun;
|
||||
u64 queue_designator;
|
||||
u32 length;
|
||||
u32 res1;
|
||||
u8 res2;
|
||||
u32 class;
|
||||
u8 res3;
|
||||
u32 s_id;
|
||||
u8 res4[20];
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
* struct zfcp_dbf_hba_uas - trace record for sysfs unit add store
|
||||
* @wwpn: remote port wwn
|
||||
* @fcp_lun: FCP LUN
|
||||
* @ret: return value
|
||||
*/
|
||||
struct zfcp_dbf_hba_uas {
|
||||
u64 wwpn;
|
||||
u64 fcp_lun;
|
||||
u32 ret;
|
||||
} __packed;
|
||||
|
||||
/**
|
||||
@@ -184,6 +212,7 @@ struct zfcp_dbf_hba_fces {
|
||||
* @ZFCP_DBF_HBA_BIT: bit error trace record
|
||||
* @ZFCP_DBF_HBA_BASIC: basic adapter event, only trace tag, no other data
|
||||
* @ZFCP_DBF_HBA_FCES: FC Endpoint Security trace record
|
||||
* @ZFCP_DBF_HBA_UAS: unit add store trace record
|
||||
*/
|
||||
enum zfcp_dbf_hba_id {
|
||||
ZFCP_DBF_HBA_RES = 1,
|
||||
@@ -191,6 +220,7 @@ enum zfcp_dbf_hba_id {
|
||||
ZFCP_DBF_HBA_BIT = 3,
|
||||
ZFCP_DBF_HBA_BASIC = 4,
|
||||
ZFCP_DBF_HBA_FCES = 5,
|
||||
ZFCP_DBF_HBA_UAS = 6,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -207,6 +237,7 @@ enum zfcp_dbf_hba_id {
|
||||
* @u.uss: data for unsolicited status buffer
|
||||
* @u.be: data for bit error unsolicited status buffer
|
||||
* @u.fces: data for FC Endpoint Security
|
||||
* @u.uas: data for unit add store
|
||||
*/
|
||||
struct zfcp_dbf_hba {
|
||||
u8 id;
|
||||
@@ -221,6 +252,7 @@ struct zfcp_dbf_hba {
|
||||
struct zfcp_dbf_hba_uss uss;
|
||||
struct fsf_bit_error_payload be;
|
||||
struct zfcp_dbf_hba_fces fces;
|
||||
struct zfcp_dbf_hba_uas uas;
|
||||
} u;
|
||||
} __packed;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* External function declarations.
|
||||
*
|
||||
* Copyright IBM Corp. 2002, 2023
|
||||
* Copyright IBM Corp. 2002, 2026
|
||||
*/
|
||||
|
||||
#ifndef ZFCP_EXT_H
|
||||
@@ -49,6 +49,8 @@ extern void zfcp_dbf_hba_fsf_fces(char *tag, const struct zfcp_fsf_req *req,
|
||||
extern void zfcp_dbf_hba_fsf_reqid(const char *const tag, const int level,
|
||||
struct zfcp_adapter *const adapter,
|
||||
const u64 req_id);
|
||||
extern void zfcp_dbf_hba_uas(char *tag, int level, struct zfcp_adapter *adapter,
|
||||
u64 wwpn, u64 fcp_lun, int ret);
|
||||
extern void zfcp_dbf_hba_bit_err(char *, struct zfcp_fsf_req *);
|
||||
extern void zfcp_dbf_hba_def_err(struct zfcp_adapter *, u64, u16, void **);
|
||||
extern void zfcp_dbf_san_req(char *, struct zfcp_fsf_req *, u32);
|
||||
@@ -152,7 +154,8 @@ extern ssize_t zfcp_fsf_scnprint_fc_security(char *buf, size_t size,
|
||||
/* zfcp_qdio.c */
|
||||
extern int zfcp_qdio_setup(struct zfcp_adapter *);
|
||||
extern void zfcp_qdio_destroy(struct zfcp_qdio *);
|
||||
extern int zfcp_qdio_sbal_get(struct zfcp_qdio *);
|
||||
extern int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
|
||||
__must_hold(qdio->req_q_lock);
|
||||
extern int zfcp_qdio_send(struct zfcp_qdio *, struct zfcp_qdio_req *);
|
||||
extern int zfcp_qdio_sbals_from_sg(struct zfcp_qdio *, struct zfcp_qdio_req *,
|
||||
struct scatterlist *);
|
||||
|
||||
@@ -246,7 +246,9 @@ struct fsf_status_read_buffer {
|
||||
u8 d_id[3];
|
||||
u32 class;
|
||||
u64 fcp_lun;
|
||||
u8 res3[24];
|
||||
u8 res3;
|
||||
u8 s_id[3];
|
||||
u8 res4[20];
|
||||
union {
|
||||
u8 data[FSF_STATUS_READ_PAYLOAD_SIZE];
|
||||
u32 word[FSF_STATUS_READ_PAYLOAD_SIZE/sizeof(u32)];
|
||||
|
||||
@@ -281,6 +281,7 @@ static int zfcp_qdio_sbal_check(struct zfcp_qdio *qdio)
|
||||
* Returns: 0 on success, -EIO if there is no free sbal after waiting.
|
||||
*/
|
||||
int zfcp_qdio_sbal_get(struct zfcp_qdio *qdio)
|
||||
__must_hold(qdio->req_q_lock)
|
||||
{
|
||||
long ret;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* sysfs attributes.
|
||||
*
|
||||
* Copyright IBM Corp. 2008, 2020
|
||||
* Copyright IBM Corp. 2008, 2026
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "zfcp: " fmt
|
||||
@@ -442,17 +442,24 @@ static ssize_t zfcp_sysfs_unit_add_store(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct zfcp_port *port = container_of(dev, struct zfcp_port, dev);
|
||||
u64 fcp_lun;
|
||||
int retval;
|
||||
struct zfcp_adapter *adapter = port->adapter;
|
||||
u64 fcp_lun = 0;
|
||||
int retval = -EINVAL;
|
||||
|
||||
if (kstrtoull(buf, 0, (unsigned long long *) &fcp_lun))
|
||||
return -EINVAL;
|
||||
if (kstrtoull(buf, 0, (unsigned long long *)&fcp_lun)) {
|
||||
zfcp_dbf_hba_uas("syuast1", 3, adapter, port->wwpn,
|
||||
fcp_lun, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
flush_work(&port->rport_work);
|
||||
|
||||
retval = zfcp_unit_add(port, fcp_lun);
|
||||
if (retval)
|
||||
if (retval) {
|
||||
zfcp_dbf_hba_uas("syuast2", 3, adapter, port->wwpn,
|
||||
fcp_lun, retval);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
@@ -499,6 +499,7 @@ source "drivers/scsi/esas2r/Kconfig"
|
||||
source "drivers/scsi/megaraid/Kconfig.megaraid"
|
||||
source "drivers/scsi/mpt3sas/Kconfig"
|
||||
source "drivers/scsi/mpi3mr/Kconfig"
|
||||
source "drivers/scsi/leapraid/Kconfig"
|
||||
source "drivers/scsi/smartpqi/Kconfig"
|
||||
|
||||
config SCSI_HPTIOP
|
||||
|
||||
@@ -91,6 +91,7 @@ obj-$(CONFIG_SCSI_BFA_FC) += bfa/
|
||||
obj-$(CONFIG_SCSI_CHELSIO_FCOE) += csiostor/
|
||||
obj-$(CONFIG_SCSI_DMX3191D) += dmx3191d.o
|
||||
obj-$(CONFIG_SCSI_HPSA) += hpsa.o
|
||||
obj-$(CONFIG_SCSI_LEAPRAID) += leapraid/
|
||||
obj-$(CONFIG_SCSI_SMARTPQI) += smartpqi/
|
||||
obj-$(CONFIG_SCSI_SYM53C8XX_2) += sym53c8xx_2/
|
||||
obj-$(CONFIG_SCSI_ZALON) += zalon7xx.o
|
||||
|
||||
@@ -275,9 +275,9 @@ static void a2091_remove(struct zorro_dev *z)
|
||||
}
|
||||
|
||||
static struct zorro_device_id a2091_zorro_tbl[] = {
|
||||
{ ZORRO_PROD_CBM_A590_A2091_1 },
|
||||
{ ZORRO_PROD_CBM_A590_A2091_2 },
|
||||
{ 0 }
|
||||
{ .id = ZORRO_PROD_CBM_A590_A2091_1 },
|
||||
{ .id = ZORRO_PROD_CBM_A590_A2091_2 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(zorro, a2091_zorro_tbl);
|
||||
|
||||
|
||||
@@ -1083,7 +1083,7 @@ static int isa_registered;
|
||||
#ifdef CONFIG_PNP
|
||||
static const struct pnp_device_id aha1542_pnp_ids[] = {
|
||||
{ .id = "ADP1542" },
|
||||
{ .id = "" }
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pnp, aha1542_pnp_ids);
|
||||
|
||||
|
||||
@@ -2182,7 +2182,6 @@ static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
|
||||
{
|
||||
struct DeviceCtlBlk *dcb = srb->dcb;
|
||||
u8 bval;
|
||||
int fact;
|
||||
|
||||
if (srb->msgin_buf[4] > 15)
|
||||
srb->msgin_buf[4] = 15;
|
||||
@@ -2205,11 +2204,6 @@ static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
|
||||
dcb->sync_period |= ALT_SYNC | bval;
|
||||
dcb->min_nego_period = srb->msgin_buf[3];
|
||||
|
||||
if (dcb->sync_period & WIDE_SYNC)
|
||||
fact = 500;
|
||||
else
|
||||
fact = 250;
|
||||
|
||||
if (!(srb->state & SRB_DO_SYNC_NEGO)) {
|
||||
/* Reply with corrected SDTR Message */
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* Copyright (C) 2007-2010 Hannes Reinecke, SUSE Linux Products GmbH.
|
||||
* All rights reserved.
|
||||
*/
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
@@ -693,8 +694,8 @@ static int alua_rtpg(struct scsi_device *sdev, struct alua_port_group *pg)
|
||||
!(tmp_pg->flags & ALUA_PG_RUNNING)) {
|
||||
struct alua_dh_data *h;
|
||||
|
||||
tmp_pg->state = desc[0] & 0x0f;
|
||||
tmp_pg->pref = desc[0] >> 7;
|
||||
tmp_pg->state = FIELD_GET(SCSI_ACCESS_STATE_MASK, desc[0]);
|
||||
tmp_pg->pref = FIELD_GET(SCSI_ACCESS_STATE_PREFERRED, desc[0]);
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(h,
|
||||
&tmp_pg->dh_list, node) {
|
||||
|
||||
@@ -6,6 +6,7 @@ fnic-y := \
|
||||
fnic_attrs.o \
|
||||
fnic_isr.o \
|
||||
fnic_main.o \
|
||||
fnic_nvme.o \
|
||||
fnic_res.o \
|
||||
fnic_fcs.o \
|
||||
fdls_disc.o \
|
||||
|
||||
@@ -21,6 +21,18 @@
|
||||
#define FCPIO_HOST_SEQ_ID_RANGE_START 0x80
|
||||
#define FCPIO_HOST_SEQ_ID_RANGE_END 0xff
|
||||
|
||||
struct fnic_nvme_io_event {
|
||||
struct list_head links;
|
||||
struct work_struct io_work;
|
||||
void *arg1;
|
||||
};
|
||||
|
||||
struct fnic_io_event_s {
|
||||
struct list_head links;
|
||||
struct work_struct io_work;
|
||||
void *arg1;
|
||||
};
|
||||
|
||||
/*
|
||||
* Command entry type
|
||||
*/
|
||||
@@ -33,6 +45,9 @@ enum fcpio_type {
|
||||
FCPIO_ICMND_CMPL,
|
||||
FCPIO_ITMF,
|
||||
FCPIO_ITMF_CMPL,
|
||||
FCPIO_NVME_CMD,
|
||||
FCPIO_NVME_ERSP_HW_CMPL,
|
||||
FCPIO_NVME_ERSP_FW_CMPL,
|
||||
|
||||
/*
|
||||
* Target request types
|
||||
@@ -179,10 +194,22 @@ fcpio_header_dec(struct fcpio_header *hdr,
|
||||
*tag = hdr->tag;
|
||||
}
|
||||
|
||||
#define NVME_CMD_SZ 96
|
||||
#define CDB_16 16
|
||||
#define CDB_32 32
|
||||
#define LUN_ADDRESS 8
|
||||
|
||||
struct fcpio_nvme_cmnd {
|
||||
uint8_t d_id[3];
|
||||
u_int8_t flags; /* command flags */
|
||||
u_int32_t sgl_cnt; /* scatter-gather list count */
|
||||
u_int64_t sgl_addr; /* scatter-gather list addr */
|
||||
u_int16_t cmd_len;
|
||||
u_int16_t _resvd1; /* reserved: should be 0 */
|
||||
u_int32_t data_len; /* length of data expected */
|
||||
u_int8_t nvme_cmnd[NVME_CMD_SZ]; /* NVME command */
|
||||
};
|
||||
|
||||
/*
|
||||
* fcpio_icmnd_16: host -> firmware request
|
||||
*
|
||||
@@ -458,6 +485,7 @@ struct fcpio_host_req {
|
||||
/*
|
||||
* Initiator host requests
|
||||
*/
|
||||
struct fcpio_nvme_cmnd nvcmnd;
|
||||
struct fcpio_icmnd_16 icmnd_16;
|
||||
struct fcpio_icmnd_32 icmnd_32;
|
||||
struct fcpio_itmf itmf;
|
||||
@@ -482,6 +510,12 @@ struct fcpio_host_req {
|
||||
} u;
|
||||
};
|
||||
|
||||
struct fcpio_nvme_cmpl {
|
||||
uint8_t resp_size;
|
||||
uint8_t resvd[3];
|
||||
uint8_t resp_bytes[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* fcpio_icmnd_cmpl: firmware -> host response
|
||||
*
|
||||
@@ -682,6 +716,7 @@ struct fcpio_fw_req {
|
||||
* Initiator firmware responses
|
||||
*/
|
||||
struct fcpio_icmnd_cmpl icmnd_cmpl;
|
||||
struct fcpio_nvme_cmpl nvme_cmpl;
|
||||
struct fcpio_itmf_cmpl itmf_cmpl;
|
||||
|
||||
/*
|
||||
|
||||
+572
-406
File diff suppressed because it is too large
Load Diff
@@ -30,6 +30,9 @@
|
||||
#include <linux/if_ether.h>
|
||||
#include <scsi/fc/fc_encaps.h>
|
||||
#include <scsi/fc/fc_fcoe.h>
|
||||
#include <linux/nvme.h>
|
||||
#include <linux/nvme-fc.h>
|
||||
#include <linux/nvme-fc-driver.h>
|
||||
|
||||
#define FDLS_MIN_FRAMES (32)
|
||||
#define FDLS_MIN_FRAME_ELEM (4)
|
||||
@@ -39,6 +42,9 @@
|
||||
#define FNIC_FCP_SP_CONF_CMPL 0x00000080
|
||||
#define FNIC_FCP_SP_RETRY 0x00000100
|
||||
|
||||
#define FNIC_NVME_SP_INITIATOR 0x00000020
|
||||
#define FNIC_NVME_SP_SLER 0x00000100
|
||||
|
||||
#define FNIC_FC_CONCUR_SEQS (0xFF)
|
||||
#define FNIC_FC_RO_INFO (0x1F)
|
||||
|
||||
@@ -50,6 +56,7 @@
|
||||
|
||||
#define FNIC_FCP_RSP_FCTL (0x000099)
|
||||
#define FNIC_REQ_ABTS_FCTL (0x000009)
|
||||
#define FNIC_NVME_LS_REQ_FCTL (0x000029)
|
||||
|
||||
#define FNIC_FC_PH_VER_HI (0x20)
|
||||
#define FNIC_FC_PH_VER_LO (0x20)
|
||||
|
||||
+55
-64
@@ -27,7 +27,7 @@ void fnic_fcoe_reset_vlans(struct fnic *fnic)
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&fnic->vlans_lock, flags);
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Reset vlan complete\n");
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ void fnic_fcoe_send_vlan_req(struct fnic *fnic)
|
||||
|
||||
frame = fdls_alloc_frame(iport);
|
||||
if (frame == NULL) {
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic,
|
||||
"Failed to allocate frame to send VLAN req");
|
||||
return;
|
||||
}
|
||||
@@ -54,10 +54,10 @@ void fnic_fcoe_send_vlan_req(struct fnic *fnic)
|
||||
fnic_fcoe_reset_vlans(fnic);
|
||||
|
||||
fnic->set_vlan(fnic, 0);
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"set vlan done\n");
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"got MAC 0x%x:%x:%x:%x:%x:%x\n", iport->hwmac[0],
|
||||
iport->hwmac[1], iport->hwmac[2], iport->hwmac[3],
|
||||
iport->hwmac[4], iport->hwmac[5]);
|
||||
@@ -81,13 +81,13 @@ void fnic_fcoe_send_vlan_req(struct fnic *fnic)
|
||||
|
||||
iport->fip.state = FDLS_FIP_VLAN_DISCOVERY_STARTED;
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Send VLAN req\n");
|
||||
fnic_send_fip_frame(iport, frame, frame_size);
|
||||
|
||||
vlan_tov = jiffies + msecs_to_jiffies(FCOE_CTLR_FIPVLAN_TOV);
|
||||
mod_timer(&fnic->retry_fip_timer, round_jiffies(vlan_tov));
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fip timer set\n");
|
||||
}
|
||||
|
||||
@@ -111,11 +111,11 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
struct fip_vlan_desc *vlan_desc;
|
||||
unsigned long flags;
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p got vlan resp\n", fnic);
|
||||
|
||||
desc_len = be16_to_cpu(vlan_notif->fip.fip_dl_len);
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"desc_len %d\n", desc_len);
|
||||
|
||||
spin_lock_irqsave(&fnic->vlans_lock, flags);
|
||||
@@ -128,23 +128,20 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
|
||||
if (vlan_desc->fd_desc.fip_dtype == FIP_DT_VLAN) {
|
||||
if (vlan_desc->fd_desc.fip_dlen != 1) {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Invalid descriptor length(%x) in VLan response\n",
|
||||
vlan_desc->fd_desc.fip_dlen);
|
||||
|
||||
}
|
||||
num_vlan++;
|
||||
vid = be16_to_cpu(vlan_desc->fd_vlan);
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"process_vlan_resp: FIP VLAN %d\n", vid);
|
||||
vlan = kzalloc_obj(*vlan);
|
||||
vlan = kzalloc_obj(*vlan, GFP_ATOMIC);
|
||||
|
||||
if (!vlan) {
|
||||
/* retry from timer */
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Mem Alloc failure\n");
|
||||
spin_unlock_irqrestore(&fnic->vlans_lock,
|
||||
flags);
|
||||
@@ -155,14 +152,14 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
list_add_tail(&vlan->list, &fnic->vlan_list);
|
||||
break;
|
||||
}
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
"Invalid descriptor type(%x) in VLan response\n",
|
||||
vlan_desc->fd_desc.fip_dtype);
|
||||
/*
|
||||
* Note : received a type=2 descriptor here i.e. FIP
|
||||
* MAC Address Descriptor
|
||||
* Note : skip any type=2 descriptor here
|
||||
* (i.e. FIP MAC Address Descriptor)
|
||||
*/
|
||||
if (vlan_desc->fd_desc.fip_dtype != FIP_DT_MAC)
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Invalid descriptor type(0x%x) in vlan response\n",
|
||||
vlan_desc->fd_desc.fip_dtype);
|
||||
cur_desc += vlan_desc->fd_desc.fip_dlen;
|
||||
desc_len -= vlan_desc->fd_desc.fip_dlen;
|
||||
}
|
||||
@@ -170,7 +167,7 @@ void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
/* any VLAN descriptors present ? */
|
||||
if (num_vlan == 0) {
|
||||
atomic64_inc(&fnic_stats->vlan_stats.resp_withno_vlanID);
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p No VLAN descriptors in FIP VLAN response\n",
|
||||
fnic);
|
||||
}
|
||||
@@ -195,7 +192,7 @@ void fnic_fcoe_start_fcf_discovery(struct fnic *fnic)
|
||||
|
||||
frame = fdls_alloc_frame(iport);
|
||||
if (frame == NULL) {
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic,
|
||||
"Failed to allocate frame to start FCF discovery");
|
||||
return;
|
||||
}
|
||||
@@ -222,7 +219,7 @@ void fnic_fcoe_start_fcf_discovery(struct fnic *fnic)
|
||||
|
||||
FNIC_STD_SET_NODE_NAME(&pdisc_sol->name_desc.fd_wwn, iport->wwnn);
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Start FCF discovery\n");
|
||||
fnic_send_fip_frame(iport, frame, frame_size);
|
||||
|
||||
@@ -257,16 +254,14 @@ void fnic_fcoe_fip_discovery_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
switch (iport->fip.state) {
|
||||
case FDLS_FIP_FCF_DISCOVERY_STARTED:
|
||||
if (be16_to_cpu(disc_adv->fip.fip_flags) & FIP_FL_SOL) {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p Solicited adv\n", fnic);
|
||||
|
||||
if ((disc_adv->prio_desc.fd_pri <
|
||||
iport->selected_fcf.fcf_priority)
|
||||
&& (be16_to_cpu(disc_adv->fip.fip_flags) & FIP_FL_AVAIL)) {
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p FCF Available\n", fnic);
|
||||
memcpy(iport->selected_fcf.fcf_mac,
|
||||
disc_adv->mac_desc.fd_mac, ETH_ALEN);
|
||||
@@ -274,8 +269,8 @@ void fnic_fcoe_fip_discovery_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
disc_adv->prio_desc.fd_pri;
|
||||
iport->selected_fcf.fka_adv_period =
|
||||
be32_to_cpu(disc_adv->fka_adv_desc.fd_fka_period);
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num, "adv time %d",
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"adv time %d",
|
||||
iport->selected_fcf.fka_adv_period);
|
||||
iport->selected_fcf.ka_disabled =
|
||||
(disc_adv->fka_adv_desc.fd_flags & 1);
|
||||
@@ -294,8 +289,7 @@ void fnic_fcoe_fip_discovery_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
iport->selected_fcf.fka_adv_period =
|
||||
be32_to_cpu(disc_adv->fka_adv_desc.fd_fka_period);
|
||||
FNIC_FIP_DBG(KERN_INFO,
|
||||
fnic->host,
|
||||
fnic->fnic_num,
|
||||
fnic,
|
||||
"change fka to %d",
|
||||
iport->selected_fcf.fka_adv_period);
|
||||
}
|
||||
@@ -362,7 +356,7 @@ void fnic_fcoe_start_flogi(struct fnic *fnic)
|
||||
|
||||
frame = fdls_alloc_frame(iport);
|
||||
if (frame == NULL) {
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic,
|
||||
"Failed to allocate frame to start FIP FLOGI");
|
||||
return;
|
||||
}
|
||||
@@ -415,7 +409,7 @@ void fnic_fcoe_start_flogi(struct fnic *fnic)
|
||||
oxid = fdls_alloc_oxid(iport, FNIC_FRAME_TYPE_FABRIC_FLOGI,
|
||||
&iport->active_oxid_fabric_req);
|
||||
if (oxid == FNIC_UNASSIGNED_OXID) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Failed to allocate OXID to send FIP FLOGI");
|
||||
mempool_free(frame, fnic->frame_pool);
|
||||
return;
|
||||
@@ -427,7 +421,7 @@ void fnic_fcoe_start_flogi(struct fnic *fnic)
|
||||
FNIC_STD_SET_NODE_NAME(&pflogi_req->flogi_desc.flogi.els.fl_wwnn,
|
||||
iport->wwnn);
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"FIP start FLOGI\n");
|
||||
fnic_send_fip_frame(iport, frame, frame_size);
|
||||
iport->fip.flogi_retry++;
|
||||
@@ -457,11 +451,11 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
struct fnic_stats *fnic_stats = &fnic->fnic_stats;
|
||||
struct fc_frame_header *fchdr = &flogi_rsp->rsp_desc.flogi.fchdr;
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p FIP FLOGI rsp\n", fnic);
|
||||
desc_len = be16_to_cpu(flogi_rsp->fip.fip_dl_len);
|
||||
if (desc_len != 38) {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Invalid Descriptor List len (%x). Dropping frame\n",
|
||||
desc_len);
|
||||
return;
|
||||
@@ -471,7 +465,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
&& (flogi_rsp->rsp_desc.fd_desc.fip_dlen == 36))
|
||||
|| !((flogi_rsp->mac_desc.fd_desc.fip_dtype == 2)
|
||||
&& (flogi_rsp->mac_desc.fd_desc.fip_dlen == 2))) {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Dropping frame invalid type and len mix\n");
|
||||
return;
|
||||
}
|
||||
@@ -484,7 +478,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
|| (s_id != FC_FID_FLOGI)
|
||||
|| (frame_type != FNIC_FABRIC_FLOGI_RSP)
|
||||
|| (fchdr->fh_type != 0x01)) {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Dropping invalid frame: s_id %x F %x R %x t %x OX_ID %x\n",
|
||||
s_id, fchdr->fh_f_ctl[0], fchdr->fh_r_ctl,
|
||||
fchdr->fh_type, FNIC_STD_GET_OX_ID(fchdr));
|
||||
@@ -492,7 +486,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
}
|
||||
|
||||
if (iport->fip.state == FDLS_FIP_FLOGI_STARTED) {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p rsp for pending FLOGI\n", fnic);
|
||||
|
||||
oxid = FNIC_STD_GET_OX_ID(fchdr);
|
||||
@@ -502,8 +496,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
if ((be16_to_cpu(flogi_rsp->fip.fip_dl_len) == FIP_FLOGI_LEN)
|
||||
&& (flogi_rsp->rsp_desc.flogi.els.fl_cmd == ELS_LS_ACC)) {
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p FLOGI success\n", fnic);
|
||||
memcpy(iport->fpma, flogi_rsp->mac_desc.fd_mac, ETH_ALEN);
|
||||
iport->fcid =
|
||||
@@ -519,8 +512,7 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
|
||||
if (fnic_fdls_register_portid(iport, iport->fcid, NULL)
|
||||
!= 0) {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p flogi registration failed\n",
|
||||
fnic);
|
||||
return;
|
||||
@@ -528,8 +520,8 @@ void fnic_fcoe_process_flogi_resp(struct fnic *fnic, struct fip_header *fiph)
|
||||
|
||||
iport->fip.state = FDLS_FIP_FLOGI_COMPLETE;
|
||||
iport->state = FNIC_IPORT_STATE_FABRIC_DISC;
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num, "iport->state:%d\n",
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"iport->state:%d\n",
|
||||
iport->state);
|
||||
fnic_fdls_disc_start(iport);
|
||||
if (!((iport->selected_fcf.ka_disabled)
|
||||
@@ -575,7 +567,7 @@ void fnic_common_fip_cleanup(struct fnic *fnic)
|
||||
|
||||
if (!iport->usefip)
|
||||
return;
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p fip cleanup\n", fnic);
|
||||
|
||||
iport->fip.state = FDLS_FIP_INIT;
|
||||
@@ -617,7 +609,7 @@ void fnic_fcoe_process_cvl(struct fnic *fnic, struct fip_header *fiph)
|
||||
int found = false;
|
||||
int max_count = 0;
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p clear virtual link handler\n", fnic);
|
||||
|
||||
if (!((cvl_msg->fcf_mac_desc.fd_desc.fip_dtype == 2)
|
||||
@@ -625,7 +617,7 @@ void fnic_fcoe_process_cvl(struct fnic *fnic, struct fip_header *fiph)
|
||||
|| !((cvl_msg->name_desc.fd_desc.fip_dtype == 4)
|
||||
&& (cvl_msg->name_desc.fd_desc.fip_dlen == 3))) {
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"invalid mix: ft %x fl %x ndt %x ndl %x",
|
||||
cvl_msg->fcf_mac_desc.fd_desc.fip_dtype,
|
||||
cvl_msg->fcf_mac_desc.fd_desc.fip_dlen,
|
||||
@@ -640,8 +632,7 @@ void fnic_fcoe_process_cvl(struct fnic *fnic, struct fip_header *fiph)
|
||||
if (!((cvl_msg->vn_ports_desc[i].fd_desc.fip_dtype == 11)
|
||||
&& (cvl_msg->vn_ports_desc[i].fd_desc.fip_dlen == 5))) {
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Invalid type and len mix type: %d len: %d\n",
|
||||
cvl_msg->vn_ports_desc[i].fd_desc.fip_dtype,
|
||||
cvl_msg->vn_ports_desc[i].fd_desc.fip_dlen);
|
||||
@@ -664,12 +655,12 @@ void fnic_fcoe_process_cvl(struct fnic *fnic, struct fip_header *fiph)
|
||||
spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
|
||||
max_count++;
|
||||
if (max_count >= FIP_FNIC_RESET_WAIT_COUNT) {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"Rthr waited too long. Skipping handle link event %p\n",
|
||||
fnic);
|
||||
return;
|
||||
}
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic reset in progress. Link event needs to wait %p",
|
||||
fnic);
|
||||
}
|
||||
@@ -714,7 +705,7 @@ int fdls_fip_recv_frame(struct fnic *fnic, void *frame)
|
||||
return true;
|
||||
}
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Not a FIP Frame");
|
||||
return false;
|
||||
}
|
||||
@@ -724,7 +715,7 @@ void fnic_work_on_fip_timer(struct work_struct *work)
|
||||
struct fnic *fnic = container_of(work, struct fnic, fip_timer_work);
|
||||
struct fnic_iport_s *iport = &fnic->iport;
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"FIP timeout\n");
|
||||
|
||||
if (iport->fip.state == FDLS_FIP_VLAN_DISCOVERY_STARTED) {
|
||||
@@ -732,7 +723,7 @@ void fnic_work_on_fip_timer(struct work_struct *work)
|
||||
} else if (iport->fip.state == FDLS_FIP_FCF_DISCOVERY_STARTED) {
|
||||
u8 zmac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"FCF Discovery timeout\n");
|
||||
if (memcmp(iport->selected_fcf.fcf_mac, zmac, ETH_ALEN) != 0) {
|
||||
|
||||
@@ -754,13 +745,13 @@ void fnic_work_on_fip_timer(struct work_struct *work)
|
||||
round_jiffies(fcf_tov));
|
||||
}
|
||||
} else {
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host,
|
||||
fnic->fnic_num, "FCF Discovery timeout\n");
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"FCF Discovery timeout\n");
|
||||
fnic_vlan_discovery_timeout(fnic);
|
||||
}
|
||||
} else if (iport->fip.state == FDLS_FIP_FLOGI_STARTED) {
|
||||
fdls_schedule_oxid_free(iport, &iport->active_oxid_fabric_req);
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"FLOGI timeout\n");
|
||||
if (iport->fip.flogi_retry < fnic->config.flogi_retries)
|
||||
fnic_fcoe_start_flogi(fnic);
|
||||
@@ -807,7 +798,7 @@ void fnic_handle_enode_ka_timer(struct timer_list *t)
|
||||
|
||||
frame = fdls_alloc_frame(iport);
|
||||
if (frame == NULL) {
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic,
|
||||
"Failed to allocate frame to send enode ka");
|
||||
return;
|
||||
}
|
||||
@@ -828,7 +819,7 @@ void fnic_handle_enode_ka_timer(struct timer_list *t)
|
||||
memcpy(penode_ka->eth.h_dest, iport->selected_fcf.fcf_mac, ETH_ALEN);
|
||||
memcpy(penode_ka->mac_desc.fd_mac, iport->hwmac, ETH_ALEN);
|
||||
|
||||
FNIC_FIP_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_DEBUG, fnic,
|
||||
"Handle enode KA timer\n");
|
||||
fnic_send_fip_frame(iport, frame, frame_size);
|
||||
enode_ka_tov = jiffies
|
||||
@@ -861,7 +852,7 @@ void fnic_handle_vn_ka_timer(struct timer_list *t)
|
||||
|
||||
frame = fdls_alloc_frame(iport);
|
||||
if (frame == NULL) {
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_ERR, fnic,
|
||||
"Failed to allocate frame to send vn ka");
|
||||
return;
|
||||
}
|
||||
@@ -887,7 +878,7 @@ void fnic_handle_vn_ka_timer(struct timer_list *t)
|
||||
memcpy(pvn_port_ka->vn_port_desc.fd_fc_id, fcid, 3);
|
||||
FNIC_STD_SET_NPORT_NAME(&pvn_port_ka->vn_port_desc.fd_wwpn, iport->wwpn);
|
||||
|
||||
FNIC_FIP_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_DEBUG, fnic,
|
||||
"Handle vnport KA timer\n");
|
||||
fnic_send_fip_frame(iport, frame, frame_size);
|
||||
vn_ka_tov = jiffies + msecs_to_jiffies(FIP_VN_KA_PERIOD);
|
||||
@@ -977,7 +968,7 @@ void fnic_work_on_fcs_ka_timer(struct work_struct *work)
|
||||
*fnic = container_of(work, struct fnic, fip_timer_work);
|
||||
struct fnic_iport_s *iport = &fnic->iport;
|
||||
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FIP_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p fcs ka timeout\n", fnic);
|
||||
|
||||
fnic_common_fip_cleanup(fnic);
|
||||
|
||||
@@ -142,7 +142,7 @@ fnic_debug_dump_fip_frame(struct fnic *fnic, struct ethhdr *eth,
|
||||
u16 op = be16_to_cpu(fiph->fip_op);
|
||||
u8 sub = fiph->fip_subcode;
|
||||
|
||||
FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_DEBUG, fnic,
|
||||
"FIP %s packet contents: op: 0x%x sub: 0x%x (len = %d)",
|
||||
pfx, op, sub, len);
|
||||
|
||||
|
||||
+63
-31
@@ -27,10 +27,11 @@
|
||||
#include "vnic_stats.h"
|
||||
#include "vnic_scsi.h"
|
||||
#include "fnic_fdls.h"
|
||||
#include "fnic_nvme.h"
|
||||
|
||||
#define DRV_NAME "fnic"
|
||||
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
|
||||
#define DRV_VERSION "1.8.0.3"
|
||||
#define DRV_VERSION "1.9.0.0"
|
||||
#define PFX DRV_NAME ": "
|
||||
#define DFX DRV_NAME "%d: "
|
||||
|
||||
@@ -43,6 +44,7 @@
|
||||
#define FNIC_DFLT_QUEUE_DEPTH 256
|
||||
#define FNIC_STATS_RATE_LIMIT 4 /* limit rate at which stats are pulled up */
|
||||
#define LUN0_DELAY_TIME 9
|
||||
#define FNIC_ROLE_CONFIG_MASK (0xFF0)
|
||||
|
||||
/*
|
||||
* Tag bits used for special requests.
|
||||
@@ -79,6 +81,8 @@
|
||||
#define FNIC_DEV_RST_ABTS_DONE BIT(19)
|
||||
#define FNIC_DEV_RST_TERM_DONE BIT(20)
|
||||
#define FNIC_DEV_RST_ABTS_PENDING BIT(21)
|
||||
#define FNIC_NVME_ADMIN_IO_TIMER_PENDING BIT(22)
|
||||
#define FNIC_NVME_ADMIN_IO BIT(23)
|
||||
|
||||
#define FNIC_FW_RESET_TIMEOUT 60000 /* mSec */
|
||||
#define FNIC_FCOE_MAX_CMD_LEN 16
|
||||
@@ -144,6 +148,9 @@
|
||||
#define PCI_SUBDEVICE_ID_CISCO_HELSINKI 0x02e4 /* VIC 15235 */
|
||||
#define PCI_SUBDEVICE_ID_CISCO_GOTHENBURG 0x02f2 /* VIC 15425 */
|
||||
|
||||
#define IS_FNIC_FCP_INITIATOR(fnic) (fnic->role == FNIC_ROLE_FCP_INITIATOR)
|
||||
#define IS_FNIC_NVME_INITIATOR(fnic) (fnic->role == FNIC_ROLE_NVME_INITIATOR)
|
||||
|
||||
struct fnic_pcie_device {
|
||||
u32 device;
|
||||
u8 *desc;
|
||||
@@ -234,12 +241,15 @@ extern spinlock_t reset_fnic_list_lock;
|
||||
extern struct list_head reset_fnic_list;
|
||||
extern struct workqueue_struct *reset_fnic_work_queue;
|
||||
extern struct work_struct reset_fnic_work;
|
||||
|
||||
extern struct workqueue_struct *fnic_cmpl_queue;
|
||||
|
||||
#define FNIC_MAIN_LOGGING 0x01
|
||||
#define FNIC_FCS_LOGGING 0x02
|
||||
#define FNIC_SCSI_LOGGING 0x04
|
||||
#define FNIC_ISR_LOGGING 0x08
|
||||
#define FNIC_FDLS_LOGGING 0x10
|
||||
#define FNIC_NVME_LOGGING 0x20
|
||||
#define FNIC_FIP_LOGGING 0x40
|
||||
|
||||
#define FNIC_CHECK_LOGGING(LEVEL, CMD) \
|
||||
do { \
|
||||
@@ -249,38 +259,39 @@ do { \
|
||||
} while (0); \
|
||||
} while (0)
|
||||
|
||||
#define FNIC_MAIN_DBG(kern_level, host, fnic_num, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_MAIN_LOGGING, \
|
||||
shost_printk(kern_level, host, \
|
||||
"fnic<%d>: %s: %d: " fmt, fnic_num,\
|
||||
__func__, __LINE__, ##args);)
|
||||
#define fnic_printk(kern_level, fnic, fmt, ...) \
|
||||
(IS_FNIC_FCP_INITIATOR(fnic) ? \
|
||||
shost_printk(kern_level, fnic->host, "fnic<%d>: %s: %d: " fmt, \
|
||||
fnic->fnic_num, __func__, __LINE__, ##__VA_ARGS__) : \
|
||||
printk(kern_level "fnic<%d>: %s: %d: " fmt, fnic->fnic_num, \
|
||||
__func__, __LINE__, ##__VA_ARGS__))
|
||||
|
||||
#define FNIC_FCS_DBG(kern_level, host, fnic_num, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \
|
||||
shost_printk(kern_level, host, \
|
||||
"fnic<%d>: %s: %d: " fmt, fnic_num,\
|
||||
__func__, __LINE__, ##args);)
|
||||
#define FNIC_MAIN_DBG(kern_level, fnic, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_MAIN_LOGGING, \
|
||||
fnic_printk(kern_level, fnic, fmt, ##args);)
|
||||
|
||||
#define FNIC_FIP_DBG(kern_level, host, fnic_num, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \
|
||||
shost_printk(kern_level, host, \
|
||||
"fnic<%d>: %s: %d: " fmt, fnic_num,\
|
||||
__func__, __LINE__, ##args);)
|
||||
#define FNIC_FCS_DBG(kern_level, fnic, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \
|
||||
fnic_printk(kern_level, fnic, fmt, ##args);)
|
||||
|
||||
#define FNIC_SCSI_DBG(kern_level, host, fnic_num, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_SCSI_LOGGING, \
|
||||
shost_printk(kern_level, host, \
|
||||
"fnic<%d>: %s: %d: " fmt, fnic_num,\
|
||||
__func__, __LINE__, ##args);)
|
||||
#define FNIC_FIP_DBG(kern_level, fnic, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_FIP_LOGGING, \
|
||||
fnic_printk(kern_level, fnic, fmt, ##args);)
|
||||
|
||||
#define FNIC_ISR_DBG(kern_level, host, fnic_num, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING, \
|
||||
shost_printk(kern_level, host, \
|
||||
"fnic<%d>: %s: %d: " fmt, fnic_num,\
|
||||
__func__, __LINE__, ##args);)
|
||||
#define FNIC_SCSI_DBG(kern_level, fnic, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_SCSI_LOGGING, \
|
||||
fnic_printk(kern_level, fnic, fmt, ##args);)
|
||||
|
||||
#define FNIC_MAIN_NOTE(kern_level, host, fmt, args...) \
|
||||
shost_printk(kern_level, host, fmt, ##args)
|
||||
#define FNIC_ISR_DBG(kern_level, fnic, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING, \
|
||||
fnic_printk(kern_level, fnic, fmt, ##args);)
|
||||
|
||||
#define FNIC_NVME_DBG(kern_level, fnic, fmt, args...) \
|
||||
FNIC_CHECK_LOGGING(FNIC_NVME_LOGGING, \
|
||||
fnic_printk(kern_level, fnic, fmt, ##args);)
|
||||
|
||||
#define FNIC_MAIN_NOTE(kern_level, fnic, fmt, args...) \
|
||||
fnic_printk(kern_level, fnic, fmt, ##args)
|
||||
|
||||
#define FNIC_WQ_COPY_MAX 64
|
||||
#define FNIC_WQ_MAX 1
|
||||
@@ -325,6 +336,7 @@ enum fnic_state {
|
||||
|
||||
enum fnic_role_e {
|
||||
FNIC_ROLE_FCP_INITIATOR = 0,
|
||||
FNIC_ROLE_NVME_INITIATOR,
|
||||
};
|
||||
|
||||
enum fnic_evt {
|
||||
@@ -343,6 +355,11 @@ struct fnic_frame_list {
|
||||
int rx_ethhdr_stripped;
|
||||
};
|
||||
|
||||
struct fnic_tag_t {
|
||||
struct list_head free_list;
|
||||
int tag_id;
|
||||
};
|
||||
|
||||
struct fnic_event {
|
||||
struct list_head list;
|
||||
struct fnic *fnic;
|
||||
@@ -460,6 +477,15 @@ struct fnic {
|
||||
struct list_head vlan_list;
|
||||
/*** FIP related data members -- end ***/
|
||||
|
||||
/* NVME data members */
|
||||
struct dentry *fnic_nvmef_debugfs_host;
|
||||
struct dentry *fnic_nvmef_debugfs_file;
|
||||
struct sbitmap nvfnic_tag_map;
|
||||
struct work_struct nvme_io_cmpl_work;
|
||||
atomic_t nvme_io_event_queued;
|
||||
struct llist_head nvme_io_event_llist;
|
||||
struct completion *nvme_lport_unreg_done;
|
||||
|
||||
/* copy work queue cache line section */
|
||||
____cacheline_aligned struct vnic_wq_copy hw_copy_wq[FNIC_WQ_COPY_MAX];
|
||||
____cacheline_aligned struct fnic_cpy_wq sw_copy_wq[FNIC_WQ_COPY_MAX];
|
||||
@@ -513,6 +539,7 @@ int fnic_host_reset(struct Scsi_Host *shost);
|
||||
void fnic_reset(struct Scsi_Host *shost);
|
||||
int fnic_issue_fc_host_lip(struct Scsi_Host *shost);
|
||||
void fnic_get_host_port_state(struct Scsi_Host *shost);
|
||||
void fnic_fcpio_reset(struct fnic *fnic);
|
||||
int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do, unsigned int cq_index);
|
||||
int fnic_wq_cmpl_handler(struct fnic *fnic, int);
|
||||
int fnic_flogi_reg_handler(struct fnic *fnic, u32);
|
||||
@@ -526,6 +553,9 @@ void fnic_log_q_error(struct fnic *fnic);
|
||||
void fnic_handle_link_event(struct fnic *fnic);
|
||||
int fnic_stats_debugfs_init(struct fnic *fnic);
|
||||
void fnic_stats_debugfs_remove(struct fnic *fnic);
|
||||
void fnic_nvmef_debugfs_init(struct fnic *fnic);
|
||||
void fnic_nvmef_debugfs_remove(struct fnic *fnic);
|
||||
int nvfnic_get_nvmef_info(struct fnic *fnic, struct fnic_nvmef_info *info);
|
||||
int fnic_is_abts_pending(struct fnic *, struct scsi_cmnd *);
|
||||
|
||||
void fnic_handle_fip_frame(struct work_struct *work);
|
||||
@@ -559,6 +589,8 @@ void fnic_scsi_unload(struct fnic *fnic);
|
||||
void fnic_scsi_unload_cleanup(struct fnic *fnic);
|
||||
int fnic_get_debug_info(struct stats_debug_info *info,
|
||||
struct fnic *fnic);
|
||||
int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq,
|
||||
unsigned int hwq);
|
||||
|
||||
struct fnic_scsi_iter_data {
|
||||
struct fnic *fnic;
|
||||
@@ -598,7 +630,7 @@ fnic_debug_dump(struct fnic *fnic, uint8_t *u8arr, int len)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < len; i = i+8) {
|
||||
FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"%d: %02x %02x %02x %02x %02x %02x %02x %02x", i / 8,
|
||||
u8arr[i + 0], u8arr[i + 1], u8arr[i + 2], u8arr[i + 3],
|
||||
u8arr[i + 4], u8arr[i + 5], u8arr[i + 6], u8arr[i + 7]);
|
||||
@@ -613,7 +645,7 @@ fnic_debug_dump_fc_frame(struct fnic *fnic, struct fc_frame_header *fchdr,
|
||||
|
||||
s_id = ntoh24(fchdr->fh_s_id);
|
||||
d_id = ntoh24(fchdr->fh_d_id);
|
||||
FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"%s packet contents: sid/did/type/oxid = 0x%x/0x%x/0x%x/0x%x (len = %d)\n",
|
||||
pfx, s_id, d_id, fchdr->fh_type,
|
||||
FNIC_STD_GET_OX_ID(fchdr), len);
|
||||
|
||||
@@ -10,10 +10,19 @@
|
||||
extern int fnic_get_debug_info(struct stats_debug_info *debug_buffer,
|
||||
struct fnic *fnic);
|
||||
|
||||
static int fnic_nvmef_debugfs_open(struct inode *inode,
|
||||
struct file *file);
|
||||
static ssize_t fnic_nvmef_debugfs_read(struct file *file,
|
||||
char __user *ubuf,
|
||||
size_t nbytes, loff_t *pos);
|
||||
static int fnic_nvmef_debugfs_release(struct inode *inode,
|
||||
struct file *file);
|
||||
|
||||
static struct dentry *fnic_trace_debugfs_root;
|
||||
static struct dentry *fnic_trace_debugfs_file;
|
||||
static struct dentry *fnic_trace_enable;
|
||||
static struct dentry *fnic_stats_debugfs_root;
|
||||
static struct dentry *fnic_nvmef_debugfs_root;
|
||||
|
||||
static struct dentry *fnic_fc_trace_debugfs_file;
|
||||
static struct dentry *fnic_fc_rdata_trace_debugfs_file;
|
||||
@@ -46,6 +55,9 @@ int fnic_debugfs_init(void)
|
||||
fnic_stats_debugfs_root = debugfs_create_dir("statistics",
|
||||
fnic_trace_debugfs_root);
|
||||
|
||||
fnic_nvmef_debugfs_root = debugfs_create_dir("nvme_info",
|
||||
fnic_trace_debugfs_root);
|
||||
|
||||
/* Allocate memory to structure */
|
||||
fc_trc_flag = vmalloc(sizeof(struct fc_trace_flag_type));
|
||||
|
||||
@@ -70,6 +82,9 @@ int fnic_debugfs_init(void)
|
||||
*/
|
||||
void fnic_debugfs_terminate(void)
|
||||
{
|
||||
debugfs_remove(fnic_nvmef_debugfs_root);
|
||||
fnic_nvmef_debugfs_root = NULL;
|
||||
|
||||
debugfs_remove(fnic_stats_debugfs_root);
|
||||
fnic_stats_debugfs_root = NULL;
|
||||
|
||||
@@ -669,6 +684,13 @@ static const struct file_operations fnic_reset_debugfs_fops = {
|
||||
.release = fnic_reset_stats_release,
|
||||
};
|
||||
|
||||
static const struct file_operations fnic_nvmef_debugfs_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fnic_nvmef_debugfs_open,
|
||||
.read = fnic_nvmef_debugfs_read,
|
||||
.release = fnic_nvmef_debugfs_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* fnic_stats_init - Initialize stats struct and create stats file per fnic
|
||||
*
|
||||
@@ -681,7 +703,10 @@ int fnic_stats_debugfs_init(struct fnic *fnic)
|
||||
{
|
||||
char name[16];
|
||||
|
||||
snprintf(name, sizeof(name), "host%d", fnic->host->host_no);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
snprintf(name, sizeof(name), "host%d", fnic->host->host_no);
|
||||
else if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
snprintf(name, sizeof(name), "nvfnic%d", fnic->fnic_num);
|
||||
|
||||
fnic->fnic_stats_debugfs_host = debugfs_create_dir(name,
|
||||
fnic_stats_debugfs_root);
|
||||
@@ -719,3 +744,75 @@ void fnic_stats_debugfs_remove(struct fnic *fnic)
|
||||
debugfs_remove(fnic->fnic_stats_debugfs_host);
|
||||
fnic->fnic_stats_debugfs_host = NULL;
|
||||
}
|
||||
|
||||
void fnic_nvmef_debugfs_init(struct fnic *fnic)
|
||||
{
|
||||
char name[16];
|
||||
|
||||
snprintf(name, sizeof(name), "host%d", fnic->fnic_num);
|
||||
|
||||
fnic->fnic_nvmef_debugfs_host = debugfs_create_dir(name,
|
||||
fnic_nvmef_debugfs_root);
|
||||
fnic->fnic_nvmef_debugfs_file = debugfs_create_file("nvmef_info",
|
||||
S_IFREG | 0444,
|
||||
fnic->fnic_nvmef_debugfs_host,
|
||||
fnic,
|
||||
&fnic_nvmef_debugfs_fops);
|
||||
}
|
||||
|
||||
static int fnic_nvmef_debugfs_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
|
||||
struct fnic *fnic = inode->i_private;
|
||||
struct fnic_nvmef_info *info;
|
||||
int buf_size = 2 * PAGE_SIZE;
|
||||
|
||||
info = kzalloc_obj(struct fnic_nvmef_info, GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->info_buffer = vmalloc(buf_size);
|
||||
if (!info->info_buffer) {
|
||||
kfree(info);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info->buf_size = buf_size;
|
||||
memset((void *)info->info_buffer, 0, buf_size);
|
||||
info->buffer_len = nvfnic_get_nvmef_info(fnic, info);
|
||||
|
||||
file->private_data = info;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t fnic_nvmef_debugfs_read(struct file *file,
|
||||
char __user *ubuf,
|
||||
size_t nbytes, loff_t *pos)
|
||||
{
|
||||
struct fnic_nvmef_info *info = file->private_data;
|
||||
|
||||
return simple_read_from_buffer(ubuf, nbytes, pos,
|
||||
info->info_buffer, info->buffer_len);
|
||||
}
|
||||
|
||||
static int fnic_nvmef_debugfs_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct fnic_nvmef_info *info = file->private_data;
|
||||
|
||||
vfree(info->info_buffer);
|
||||
kfree(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void fnic_nvmef_debugfs_remove(struct fnic *fnic)
|
||||
{
|
||||
if (!fnic)
|
||||
return;
|
||||
|
||||
debugfs_remove(fnic->fnic_nvmef_debugfs_file);
|
||||
fnic->fnic_nvmef_debugfs_file = NULL;
|
||||
|
||||
debugfs_remove(fnic->fnic_nvmef_debugfs_host);
|
||||
fnic->fnic_nvmef_debugfs_host = NULL;
|
||||
}
|
||||
|
||||
+114
-85
@@ -31,6 +31,11 @@ struct workqueue_struct *fnic_event_queue;
|
||||
|
||||
static uint8_t FCOE_ALL_FCF_MAC[6] = FC_FCOE_FLOGI_MAC;
|
||||
|
||||
static inline bool fnic_is_nvme_frame(struct fc_frame_header *fchdr)
|
||||
{
|
||||
return (fchdr->fh_type == FC_TYPE_NVME);
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal Functions
|
||||
* This function will initialize the src_mac address to be
|
||||
@@ -39,7 +44,7 @@ static uint8_t FCOE_ALL_FCF_MAC[6] = FC_FCOE_FLOGI_MAC;
|
||||
static inline void fnic_fdls_set_fcoe_srcmac(struct fnic *fnic,
|
||||
uint8_t *src_mac)
|
||||
{
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Setting src mac: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
src_mac[0], src_mac[1], src_mac[2], src_mac[3],
|
||||
src_mac[4], src_mac[5]);
|
||||
@@ -54,7 +59,7 @@ static inline void fnic_fdls_set_fcoe_srcmac(struct fnic *fnic,
|
||||
static inline void fnic_fdls_set_fcoe_dstmac(struct fnic *fnic,
|
||||
uint8_t *dst_mac)
|
||||
{
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Setting dst mac: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
dst_mac[0], dst_mac[1], dst_mac[2], dst_mac[3],
|
||||
dst_mac[4], dst_mac[5]);
|
||||
@@ -82,7 +87,7 @@ void fnic_fdls_link_status_change(struct fnic *fnic, int linkup)
|
||||
{
|
||||
struct fnic_iport_s *iport = &fnic->iport;
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"link up: %d, usefip: %d", linkup, iport->usefip);
|
||||
|
||||
spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
|
||||
@@ -90,12 +95,12 @@ void fnic_fdls_link_status_change(struct fnic *fnic, int linkup)
|
||||
if (linkup) {
|
||||
if (iport->usefip) {
|
||||
iport->state = FNIC_IPORT_STATE_FIP;
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"link up: %d, usefip: %d", linkup, iport->usefip);
|
||||
fnic_fcoe_send_vlan_req(fnic);
|
||||
} else {
|
||||
iport->state = FNIC_IPORT_STATE_FABRIC_DISC;
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"iport->state: %d", iport->state);
|
||||
fnic_fdls_disc_start(iport);
|
||||
}
|
||||
@@ -125,13 +130,13 @@ void fnic_fdls_learn_fcoe_macs(struct fnic_iport_s *iport, void *rx_frame,
|
||||
|
||||
memcpy(&fcmac[3], fcid, 3);
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"learn fcoe: dst_mac: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ethhdr->h_dest[0], ethhdr->h_dest[1],
|
||||
ethhdr->h_dest[2], ethhdr->h_dest[3],
|
||||
ethhdr->h_dest[4], ethhdr->h_dest[5]);
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"learn fcoe: fc_mac: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
fcmac[0], fcmac[1], fcmac[2], fcmac[3], fcmac[4],
|
||||
fcmac[5]);
|
||||
@@ -149,13 +154,12 @@ void fnic_fdls_init(struct fnic *fnic, int usefip)
|
||||
iport->fnic = fnic;
|
||||
iport->usefip = usefip;
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"iportsrcmac: %02x:%02x:%02x:%02x:%02x:%02x",
|
||||
iport->hwmac[0], iport->hwmac[1], iport->hwmac[2],
|
||||
iport->hwmac[3], iport->hwmac[4], iport->hwmac[5]);
|
||||
|
||||
INIT_LIST_HEAD(&iport->tport_list);
|
||||
INIT_LIST_HEAD(&iport->tport_list_pending_del);
|
||||
|
||||
fnic_fdls_disc_init(iport);
|
||||
}
|
||||
@@ -168,14 +172,14 @@ void fnic_handle_link(struct work_struct *work)
|
||||
int max_count = 0;
|
||||
|
||||
if (vnic_dev_get_intr_mode(fnic->vdev) != VNIC_DEV_INTR_MODE_MSI)
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Interrupt mode is not MSI\n");
|
||||
|
||||
spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
|
||||
|
||||
if (fnic->stop_rx_link_events) {
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Stop link rx events\n");
|
||||
return;
|
||||
}
|
||||
@@ -184,10 +188,10 @@ void fnic_handle_link(struct work_struct *work)
|
||||
if ((fnic->state != FNIC_IN_ETH_MODE)
|
||||
&& (fnic->state != FNIC_IN_FC_MODE)) {
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"fnic in transitional state: %d. link up: %d ignored",
|
||||
fnic->state, vnic_dev_link_status(fnic->vdev));
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Current link status: %d iport state: %d\n",
|
||||
fnic->link_status, fnic->iport.state);
|
||||
return;
|
||||
@@ -199,36 +203,36 @@ void fnic_handle_link(struct work_struct *work)
|
||||
fnic->link_down_cnt = vnic_dev_link_down_cnt(fnic->vdev);
|
||||
|
||||
while (fnic->reset_in_progress == IN_PROGRESS) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"fnic reset in progress. Link event needs to wait\n");
|
||||
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"waiting for reset completion\n");
|
||||
wait_for_completion_timeout(&fnic->reset_completion_wait,
|
||||
msecs_to_jiffies(5000));
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"woken up from reset completion wait\n");
|
||||
spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
|
||||
|
||||
max_count++;
|
||||
if (max_count >= MAX_RESET_WAIT_COUNT) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Rstth waited for too long. Skipping handle link event\n");
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
return;
|
||||
}
|
||||
}
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Marking fnic reset in progress\n");
|
||||
fnic->reset_in_progress = IN_PROGRESS;
|
||||
|
||||
if ((vnic_dev_get_intr_mode(fnic->vdev) != VNIC_DEV_INTR_MODE_MSI) ||
|
||||
(fnic->link_status != old_link_status)) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"old link status: %d link status: %d\n",
|
||||
old_link_status, (int) fnic->link_status);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"old down count %d down count: %d\n",
|
||||
old_link_down_cnt, (int) fnic->link_down_cnt);
|
||||
}
|
||||
@@ -237,36 +241,36 @@ void fnic_handle_link(struct work_struct *work)
|
||||
if (!fnic->link_status) {
|
||||
/* DOWN -> DOWN */
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"down->down\n");
|
||||
} else {
|
||||
if (old_link_down_cnt != fnic->link_down_cnt) {
|
||||
/* UP -> DOWN -> UP */
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"up->down. Link down\n");
|
||||
fnic_fdls_link_status_change(fnic, 0);
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"down->up. Link up\n");
|
||||
fnic_fdls_link_status_change(fnic, 1);
|
||||
} else {
|
||||
/* UP -> UP */
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"up->up\n");
|
||||
}
|
||||
}
|
||||
} else if (fnic->link_status) {
|
||||
/* DOWN -> UP */
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"down->up. Link up\n");
|
||||
fnic_fdls_link_status_change(fnic, 1);
|
||||
} else {
|
||||
/* UP -> DOWN */
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"up->down. Link down\n");
|
||||
fnic_fdls_link_status_change(fnic, 0);
|
||||
}
|
||||
@@ -275,7 +279,7 @@ void fnic_handle_link(struct work_struct *work)
|
||||
fnic->reset_in_progress = NOT_IN_PROGRESS;
|
||||
complete(&fnic->reset_completion_wait);
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Marking fnic reset completion\n");
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
}
|
||||
@@ -285,6 +289,7 @@ void fnic_handle_frame(struct work_struct *work)
|
||||
struct fnic *fnic = container_of(work, struct fnic, frame_work);
|
||||
struct fnic_frame_list *cur_frame, *next;
|
||||
int fchdr_offset = 0;
|
||||
struct fc_frame_header *fchdr;
|
||||
|
||||
spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
|
||||
list_for_each_entry_safe(cur_frame, next, &fnic->frame_queue, links) {
|
||||
@@ -302,7 +307,7 @@ void fnic_handle_frame(struct work_struct *work)
|
||||
*/
|
||||
if (fnic->state != FNIC_IN_FC_MODE &&
|
||||
fnic->state != FNIC_IN_ETH_MODE) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Cannot process frame in transitional state\n");
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, fnic->lock_flags);
|
||||
return;
|
||||
@@ -314,8 +319,14 @@ void fnic_handle_frame(struct work_struct *work)
|
||||
fchdr_offset = (cur_frame->rx_ethhdr_stripped) ?
|
||||
0 : FNIC_ETH_FCOE_HDRS_OFFSET;
|
||||
|
||||
fnic_fdls_recv_frame(&fnic->iport, cur_frame->fp,
|
||||
cur_frame->frame_len, fchdr_offset);
|
||||
fchdr = (struct fc_frame_header *)((u8 *)cur_frame->fp + fchdr_offset);
|
||||
if (IS_FNIC_NVME_INITIATOR(fnic) && fnic_is_nvme_frame(fchdr)) {
|
||||
nvfnic_ls_rsp_recv(&fnic->iport, fchdr,
|
||||
cur_frame->frame_len - fchdr_offset);
|
||||
} else {
|
||||
fnic_fdls_recv_frame(&fnic->iport, cur_frame->fp,
|
||||
cur_frame->frame_len, fchdr_offset);
|
||||
}
|
||||
|
||||
mempool_free(cur_frame->fp, fnic->frame_recv_pool);
|
||||
mempool_free(cur_frame, fnic->frame_elem_pool);
|
||||
@@ -328,7 +339,7 @@ void fnic_handle_fip_frame(struct work_struct *work)
|
||||
struct fnic_frame_list *cur_frame, *next;
|
||||
struct fnic *fnic = container_of(work, struct fnic, fip_frame_work);
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Processing FIP frame\n");
|
||||
|
||||
spin_lock_irqsave(&fnic->fnic_lock, fnic->lock_flags);
|
||||
@@ -407,7 +418,7 @@ void fnic_update_mac_locked(struct fnic *fnic, u8 *new)
|
||||
if (ether_addr_equal(data, new))
|
||||
return;
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Update MAC: %u\n", *new);
|
||||
|
||||
if (!is_zero_ether_addr(data) && !ether_addr_equal(data, ctl))
|
||||
@@ -477,7 +488,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
|
||||
|
||||
if (!fcs_ok) {
|
||||
atomic64_inc(&fnic_stats->misc_stats.frame_errors);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"fnic 0x%p fcs error. Dropping packet.\n", fnic);
|
||||
goto drop;
|
||||
}
|
||||
@@ -487,21 +498,21 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
|
||||
if (fnic_import_rq_eth_pkt(fnic, fp))
|
||||
return;
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Dropping h_proto 0x%x",
|
||||
be16_to_cpu(eh->h_proto));
|
||||
goto drop;
|
||||
}
|
||||
} else {
|
||||
/* wrong CQ type */
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"fnic rq_cmpl wrong cq type x%x\n", type);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (!fcs_ok || packet_error || !fcoe_fnic_crc_ok || fcoe_enc_error) {
|
||||
atomic64_inc(&fnic_stats->misc_stats.frame_errors);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"fcoe %x fcsok %x pkterr %x ffco %x fee %x\n",
|
||||
fcoe, fcs_ok, packet_error,
|
||||
fcoe_fnic_crc_ok, fcoe_enc_error);
|
||||
@@ -511,7 +522,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
|
||||
spin_lock_irqsave(&fnic->fnic_lock, flags);
|
||||
if (fnic->stop_rx_link_events) {
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"fnic->stop_rx_link_events: %d\n",
|
||||
fnic->stop_rx_link_events);
|
||||
goto drop;
|
||||
@@ -521,7 +532,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc
|
||||
|
||||
frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC);
|
||||
if (!frame_elem) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Failed to allocate memory for frame elem");
|
||||
goto drop;
|
||||
}
|
||||
@@ -567,7 +578,7 @@ int fnic_rq_cmpl_handler(struct fnic *fnic, int rq_work_to_do)
|
||||
if (cur_work_done && fnic->stop_rx_link_events != 1) {
|
||||
err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame);
|
||||
if (err)
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"fnic_alloc_rq_frame can't alloc"
|
||||
" frame\n");
|
||||
}
|
||||
@@ -593,7 +604,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq)
|
||||
len = FNIC_FRAME_HT_ROOM;
|
||||
buf = mempool_alloc(fnic->frame_recv_pool, GFP_ATOMIC);
|
||||
if (!buf) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Unable to allocate RQ buffer of size: %d\n", len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -601,7 +612,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq)
|
||||
pa = dma_map_single(&fnic->pdev->dev, buf, len, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(&fnic->pdev->dev, pa)) {
|
||||
ret = -ENOMEM;
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"PCI mapping failed with error %d\n", ret);
|
||||
goto free_buf;
|
||||
}
|
||||
@@ -615,9 +626,13 @@ free_buf:
|
||||
|
||||
void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf)
|
||||
{
|
||||
void *rq_buf = buf->os_buf;
|
||||
void *rq_buf;
|
||||
struct fnic *fnic = vnic_dev_priv(rq->vdev);
|
||||
|
||||
if (WARN_ON(!buf))
|
||||
return;
|
||||
|
||||
rq_buf = buf->os_buf;
|
||||
dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len,
|
||||
DMA_FROM_DEVICE);
|
||||
|
||||
@@ -642,7 +657,7 @@ static int fnic_send_frame(struct fnic *fnic, void *frame, int frame_len)
|
||||
if ((fnic_fc_trace_set_data(fnic->fnic_num,
|
||||
FNIC_FC_SEND | 0x80, (char *) frame,
|
||||
frame_len)) != 0) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"fnic ctlr frame trace error");
|
||||
}
|
||||
|
||||
@@ -650,9 +665,9 @@ static int fnic_send_frame(struct fnic *fnic, void *frame, int frame_len)
|
||||
|
||||
if (!vnic_wq_desc_avail(wq)) {
|
||||
dma_unmap_single(&fnic->pdev->dev, pa, frame_len, DMA_TO_DEVICE);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"vnic work queue descriptor is not available");
|
||||
ret = -1;
|
||||
ret = -ENXIO;
|
||||
goto fnic_send_frame_end;
|
||||
}
|
||||
|
||||
@@ -686,7 +701,6 @@ fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size,
|
||||
struct fcoe_hdr *pfcoe_hdr;
|
||||
struct fnic_frame_list *frame_elem;
|
||||
int len = frame_size;
|
||||
int ret;
|
||||
struct fc_frame_header *fchdr = (struct fc_frame_header *) (frame +
|
||||
FNIC_ETH_FCOE_HDRS_OFFSET);
|
||||
|
||||
@@ -706,13 +720,13 @@ fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size,
|
||||
&& (fnic->state != FNIC_IN_ETH_MODE)) {
|
||||
frame_elem = mempool_alloc(fnic->frame_elem_pool, GFP_ATOMIC);
|
||||
if (!frame_elem) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Failed to allocate memory for frame elem");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(frame_elem, 0, sizeof(struct fnic_frame_list));
|
||||
|
||||
FNIC_FCS_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Queueing FC frame: sid/did/type/oxid = 0x%x/0x%x/0x%x/0x%x\n",
|
||||
ntoh24(fchdr->fh_s_id), ntoh24(fchdr->fh_d_id),
|
||||
fchdr->fh_type, FNIC_STD_GET_OX_ID(fchdr));
|
||||
@@ -724,11 +738,10 @@ fdls_send_fcoe_frame(struct fnic *fnic, void *frame, int frame_size,
|
||||
|
||||
fnic_debug_dump_fc_frame(fnic, fchdr, frame_size, "Outgoing");
|
||||
|
||||
ret = fnic_send_frame(fnic, frame, len);
|
||||
return ret;
|
||||
return fnic_send_frame(fnic, frame, len);
|
||||
}
|
||||
|
||||
void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
|
||||
int fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
|
||||
int frame_size)
|
||||
{
|
||||
struct fnic *fnic = iport->fnic;
|
||||
@@ -736,7 +749,7 @@ void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
|
||||
|
||||
/* If module unload is in-progress, don't send */
|
||||
if (fnic->in_remove)
|
||||
return;
|
||||
return -ESHUTDOWN;
|
||||
|
||||
if (iport->fabric.flags & FNIC_FDLS_FPMA_LEARNT) {
|
||||
srcmac = iport->fpma;
|
||||
@@ -746,7 +759,7 @@ void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
|
||||
dstmac = FCOE_ALL_FCF_MAC;
|
||||
}
|
||||
|
||||
fdls_send_fcoe_frame(fnic, frame, frame_size, srcmac, dstmac);
|
||||
return fdls_send_fcoe_frame(fnic, frame, frame_size, srcmac, dstmac);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -778,7 +791,7 @@ void fnic_flush_tx(struct work_struct *work)
|
||||
struct fc_frame *fp;
|
||||
struct fnic_frame_list *cur_frame, *next;
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Flush queued frames");
|
||||
|
||||
list_for_each_entry_safe(cur_frame, next, &fnic->tx_queue, links) {
|
||||
@@ -797,7 +810,7 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id,
|
||||
struct ethhdr *ethhdr;
|
||||
int ret;
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Setting port id: 0x%x fp: 0x%p fnic state: %d", port_id,
|
||||
fp, fnic->state);
|
||||
|
||||
@@ -810,7 +823,7 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id,
|
||||
if (fnic->state == FNIC_IN_ETH_MODE || fnic->state == FNIC_IN_FC_MODE)
|
||||
fnic->state = FNIC_IN_ETH_TRANS_FC_MODE;
|
||||
else {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Unexpected fnic state while processing FLOGI response\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -821,7 +834,7 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id,
|
||||
*/
|
||||
ret = fnic_flogi_reg_handler(fnic, port_id);
|
||||
if (ret < 0) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"FLOGI registration error ret: %d fnic state: %d\n",
|
||||
ret, fnic->state);
|
||||
if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE)
|
||||
@@ -831,7 +844,7 @@ fnic_fdls_register_portid(struct fnic_iport_s *iport, u32 port_id,
|
||||
}
|
||||
iport->fabric.flags |= FNIC_FDLS_FPMA_LEARNT;
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"FLOGI registration success\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -873,6 +886,9 @@ static void fnic_wq_complete_frame_send(struct vnic_wq *wq,
|
||||
{
|
||||
struct fnic *fnic = vnic_dev_priv(wq->vdev);
|
||||
|
||||
if (WARN_ON(!buf))
|
||||
return;
|
||||
|
||||
dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len,
|
||||
DMA_TO_DEVICE);
|
||||
mempool_free(buf->os_buf, fnic->frame_pool);
|
||||
@@ -915,6 +931,9 @@ void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf)
|
||||
{
|
||||
struct fnic *fnic = vnic_dev_priv(wq->vdev);
|
||||
|
||||
if (WARN_ON(!buf))
|
||||
return;
|
||||
|
||||
dma_unmap_single(&fnic->pdev->dev, buf->dma_addr, buf->len,
|
||||
DMA_TO_DEVICE);
|
||||
|
||||
@@ -931,7 +950,7 @@ fnic_fdls_add_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport,
|
||||
struct fc_rport_identifiers ids;
|
||||
struct rport_dd_data_s *rdd_data;
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Adding rport fcid: 0x%x", tport->fcid);
|
||||
|
||||
ids.node_name = tport->wwnn;
|
||||
@@ -943,12 +962,12 @@ fnic_fdls_add_tport(struct fnic_iport_s *iport, struct fnic_tport_s *tport,
|
||||
rport = fc_remote_port_add(fnic->host, 0, &ids);
|
||||
spin_lock_irqsave(&fnic->fnic_lock, flags);
|
||||
if (!rport) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Failed to add rport for tport: 0x%x", tport->fcid);
|
||||
return;
|
||||
}
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Added rport fcid: 0x%x", tport->fcid);
|
||||
|
||||
/* Mimic these assignments in queuecommand to avoid timing issues */
|
||||
@@ -987,7 +1006,7 @@ fnic_fdls_remove_tport(struct fnic_iport_s *iport,
|
||||
fc_remote_port_delete(rport);
|
||||
|
||||
spin_lock_irqsave(&fnic->fnic_lock, flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Deregistered and freed tport fcid: 0x%x from scsi transport fc",
|
||||
tport->fcid);
|
||||
|
||||
@@ -1014,11 +1033,14 @@ void fnic_delete_fcp_tports(struct fnic *fnic)
|
||||
|
||||
spin_lock_irqsave(&fnic->fnic_lock, flags);
|
||||
list_for_each_entry_safe(tport, next, &fnic->iport.tport_list, links) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"removing fcp rport fcid: 0x%x", tport->fcid);
|
||||
fdls_set_tport_state(tport, FDLS_TGT_STATE_OFFLINING);
|
||||
fnic_del_tport_timer_sync(fnic, tport);
|
||||
fnic_fdls_remove_tport(&fnic->iport, tport, flags);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
fnic_fdls_remove_tport(&fnic->iport, tport, flags);
|
||||
else if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_delete_tport(&fnic->iport, tport, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
}
|
||||
@@ -1041,36 +1063,40 @@ void fnic_tport_event_handler(struct work_struct *work)
|
||||
tport = cur_evt->arg1;
|
||||
switch (cur_evt->event) {
|
||||
case TGT_EV_RPORT_ADD:
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Add rport event");
|
||||
if (tport->state == FDLS_TGT_STATE_READY) {
|
||||
fnic_fdls_add_tport(&fnic->iport,
|
||||
(struct fnic_tport_s *) cur_evt->arg1, flags);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
fnic_fdls_add_tport(&fnic->iport, tport, flags);
|
||||
else if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_add_tport(fnic, tport, flags);
|
||||
} else {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Target not ready. Add rport event dropped: 0x%x",
|
||||
tport->fcid);
|
||||
}
|
||||
break;
|
||||
case TGT_EV_RPORT_DEL:
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Remove rport event");
|
||||
if (tport->state == FDLS_TGT_STATE_OFFLINING) {
|
||||
fnic_fdls_remove_tport(&fnic->iport,
|
||||
(struct fnic_tport_s *) cur_evt->arg1, flags);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
fnic_fdls_remove_tport(&fnic->iport, tport, flags);
|
||||
else if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_delete_tport(&fnic->iport, tport, flags);
|
||||
} else {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"remove rport event dropped tport fcid: 0x%x",
|
||||
tport->fcid);
|
||||
}
|
||||
break;
|
||||
case TGT_EV_TPORT_DELETE:
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Delete tport event");
|
||||
fdls_delete_tport(tport->iport, tport);
|
||||
break;
|
||||
default:
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Unknown tport event");
|
||||
break;
|
||||
}
|
||||
@@ -1110,12 +1136,15 @@ void fnic_reset_work_handler(struct work_struct *work)
|
||||
spin_unlock_irqrestore(&reset_fnic_list_lock,
|
||||
reset_fnic_list_lock_flags);
|
||||
|
||||
dev_err(&cur_fnic->pdev->dev, "fnic: <%d>: issuing a host reset\n",
|
||||
cur_fnic->fnic_num);
|
||||
host_reset_ret_code = fnic_host_reset(cur_fnic->host);
|
||||
dev_err(&cur_fnic->pdev->dev,
|
||||
"fnic: <%d>: returned from host reset with status: %d\n",
|
||||
cur_fnic->fnic_num, host_reset_ret_code);
|
||||
if (IS_FNIC_FCP_INITIATOR(cur_fnic)) {
|
||||
dev_err(&cur_fnic->pdev->dev,
|
||||
"fnic: <%d>: issuing a host reset\n",
|
||||
cur_fnic->fnic_num);
|
||||
host_reset_ret_code = fnic_host_reset(cur_fnic->host);
|
||||
dev_err(&cur_fnic->pdev->dev,
|
||||
"fnic: <%d>: returned from host reset with status: %d\n",
|
||||
cur_fnic->fnic_num, host_reset_ret_code);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&cur_fnic->fnic_lock, cur_fnic->lock_flags);
|
||||
cur_fnic->pc_rscn_handling_status =
|
||||
@@ -1142,7 +1171,7 @@ void fnic_fcpio_reset(struct fnic *fnic)
|
||||
if (unlikely(fnic->state == FNIC_IN_FC_TRANS_ETH_MODE)) {
|
||||
/* fw reset is in progress, poll for its completion */
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"fnic is in unexpected state: %d for fw_reset\n",
|
||||
fnic->state);
|
||||
return;
|
||||
@@ -1155,7 +1184,7 @@ void fnic_fcpio_reset(struct fnic *fnic)
|
||||
fnic->fw_reset_done = &fw_reset_done;
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Issuing fw reset\n");
|
||||
if (fnic_fw_reset_handler(fnic)) {
|
||||
spin_lock_irqsave(&fnic->fnic_lock, flags);
|
||||
@@ -1163,14 +1192,14 @@ void fnic_fcpio_reset(struct fnic *fnic)
|
||||
fnic->state = old_state;
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
} else {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Waiting for fw completion\n");
|
||||
time_remain = wait_for_completion_timeout(&fw_reset_done,
|
||||
msecs_to_jiffies(FNIC_FW_RESET_TIMEOUT));
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"Woken up after fw completion timeout\n");
|
||||
if (time_remain == 0) {
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_FCS_DBG(KERN_INFO, fnic,
|
||||
"FW reset completion timed out after %d ms\n",
|
||||
FNIC_FW_RESET_TIMEOUT);
|
||||
}
|
||||
|
||||
@@ -78,14 +78,17 @@
|
||||
#define FNIC_FDLS_FPMA_LEARNT 0x2
|
||||
|
||||
/* tport flags */
|
||||
#define FNIC_FDLS_TPORT_IN_GPN_FT_LIST 0x1
|
||||
#define FNIC_FDLS_TGT_ABORT_ISSUED 0x2
|
||||
#define FNIC_FDLS_TPORT_SEND_ADISC 0x4
|
||||
#define FNIC_FDLS_RETRY_FRAME 0x8
|
||||
#define FNIC_FDLS_TPORT_BUSY 0x10
|
||||
#define FNIC_FDLS_TPORT_TERMINATING 0x20
|
||||
#define FNIC_FDLS_TPORT_DELETED 0x40
|
||||
#define FNIC_FDLS_SCSI_REGISTERED 0x200
|
||||
#define FNIC_FDLS_TPORT_IN_GPN_FT_LIST 0x1
|
||||
#define FNIC_FDLS_TGT_ABORT_ISSUED 0x2
|
||||
#define FNIC_FDLS_TPORT_SEND_ADISC 0x4
|
||||
#define FNIC_FDLS_RETRY_FRAME 0x8
|
||||
#define FNIC_FDLS_TPORT_BUSY 0x10
|
||||
#define FNIC_FDLS_TPORT_TERMINATING 0x20
|
||||
#define FNIC_FDLS_TPORT_DELETED 0x40
|
||||
#define FNIC_FDLS_NVME_REGISTERED 0x80
|
||||
#define FNIC_FDLS_NVME_TPORT_CLEANUP_PENDING 0x100
|
||||
#define FNIC_FDLS_SCSI_REGISTERED 0x200
|
||||
#define FNIC_TPORT_CAN_BE_FREED 0x400
|
||||
|
||||
/* Retry supported by rport(returned by prli service parameters) */
|
||||
#define FDLS_FC_RP_FLAGS_RETRY 0x1
|
||||
@@ -94,6 +97,7 @@
|
||||
#define fdls_get_state(_fdls_fabric) ((_fdls_fabric)->state)
|
||||
|
||||
#define FNIC_FDMI_ACTIVE 0x8
|
||||
#define FNIC_LPORT_NVME_REGISTERED 0x4
|
||||
#define FNIC_FIRST_LINK_UP 0x2
|
||||
|
||||
#define fdls_set_tport_state(_tport, _state) (_tport->state = _state)
|
||||
@@ -119,6 +123,13 @@
|
||||
#define FNIC_FRAME_TYPE_TGT_PRLI 0x2800
|
||||
#define FNIC_FRAME_TYPE_TGT_ADISC 0x2A00
|
||||
#define FNIC_FRAME_TYPE_TGT_LOGO 0x2C00
|
||||
#define FNIC_FRAME_TYPE_NVME_LS 0x3000
|
||||
|
||||
#define NVFNIC_FCPIO_TAG_POOL_SZ (2048)
|
||||
#define NVFNIC_LS_REQ_OXID_POOL_SZ (64)
|
||||
#define NVFNIC_LS_REQ_OXID_BASE (0x2500)
|
||||
#define FNIC_LPORT_NVME_REGISTERED 0x4
|
||||
|
||||
|
||||
struct fnic_fip_fcf_s {
|
||||
uint16_t vlan_id;
|
||||
@@ -220,6 +231,8 @@ struct fnic_tport_s {
|
||||
struct fc_rport *rport;
|
||||
char str_wwpn[20];
|
||||
char str_wwnn[20];
|
||||
struct list_head ls_req_list;
|
||||
struct nvme_fc_remote_port *nv_rport;
|
||||
};
|
||||
|
||||
/* OXID pool related structures */
|
||||
@@ -288,7 +301,6 @@ struct fnic_iport_s {
|
||||
struct fnic_fdls_fip_s fip;
|
||||
struct fnic_fdls_fabric_s fabric;
|
||||
struct list_head tport_list;
|
||||
struct list_head tport_list_pending_del;
|
||||
/* list of tports for which we are yet to send PLOGO */
|
||||
struct list_head inprocess_tport_list;
|
||||
struct list_head deleted_tport_list;
|
||||
@@ -308,6 +320,13 @@ struct fnic_iport_s {
|
||||
struct fnic_iport_stats iport_stats;
|
||||
char str_wwpn[20];
|
||||
char str_wwnn[20];
|
||||
|
||||
/* nvme */;
|
||||
void *nvfnic_fcpio_tag[NVFNIC_FCPIO_TAG_POOL_SZ];
|
||||
struct nvme_fc_local_port *nv_lport;
|
||||
struct nvme_fc_port_template *nv_tmpl;
|
||||
struct fnic_oxid_pool_s ls_req_oxid_pool;
|
||||
struct list_head fcpio_list;
|
||||
};
|
||||
|
||||
struct rport_dd_data_s {
|
||||
@@ -336,6 +355,7 @@ enum fnic_recv_frame_type_e {
|
||||
FNIC_TPORT_ADISC_RSP,
|
||||
FNIC_TPORT_BLS_ABTS_RSP,
|
||||
FNIC_TPORT_LOGO_RSP,
|
||||
FNIC_LS_REQ_ABTS_RSP,
|
||||
|
||||
/* unsolicited requests */
|
||||
FNIC_BLS_ABTS_REQ,
|
||||
@@ -368,6 +388,12 @@ enum fnic_port_speeds {
|
||||
DCEM_PORTSPEED_128G = 128000,
|
||||
};
|
||||
|
||||
static inline bool fdls_tport_is_offline(struct fnic_tport_s *tport)
|
||||
{
|
||||
return (tport->state == FDLS_TGT_STATE_OFFLINING ||
|
||||
tport->state == FDLS_TGT_STATE_OFFLINE);
|
||||
}
|
||||
|
||||
/* Function Declarations */
|
||||
/* fdls_disc.c */
|
||||
void fnic_fdls_disc_init(struct fnic_iport_s *iport);
|
||||
@@ -381,6 +407,8 @@ uint16_t fdls_alloc_oxid(struct fnic_iport_s *iport, int oxid_frame_type,
|
||||
uint16_t *active_oxid);
|
||||
void fdls_free_oxid(struct fnic_iport_s *iport,
|
||||
uint16_t oxid, uint16_t *active_oxid);
|
||||
int fdls_send_ls_req_abts(struct fnic_iport_s *iport,
|
||||
struct fnic_tport_s *tport, unsigned int oxid);
|
||||
void fdls_tgt_logout(struct fnic_iport_s *iport,
|
||||
struct fnic_tport_s *tport);
|
||||
void fnic_del_fabric_timer_sync(struct fnic *fnic);
|
||||
@@ -398,7 +426,7 @@ void fdls_fdmi_retry_plogi(struct fnic_iport_s *iport);
|
||||
|
||||
/* fnic_fcs.c */
|
||||
void fnic_fdls_init(struct fnic *fnic, int usefip);
|
||||
void fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
|
||||
int fnic_send_fcoe_frame(struct fnic_iport_s *iport, void *frame,
|
||||
int frame_size);
|
||||
void fnic_fcoe_send_vlan_req(struct fnic *fnic);
|
||||
int fnic_send_fip_frame(struct fnic_iport_s *iport,
|
||||
|
||||
@@ -6,13 +6,19 @@
|
||||
#ifndef _FNIC_IO_H_
|
||||
#define _FNIC_IO_H_
|
||||
|
||||
#include <scsi/fc/fc_fs.h>
|
||||
#include <scsi/fc/fc_fcp.h>
|
||||
#include "fnic_fdls.h"
|
||||
#include "fcpio.h"
|
||||
#include <linux/nvme-fc-driver.h>
|
||||
|
||||
#define FNIC_DFLT_SG_DESC_CNT 32
|
||||
#define FNIC_MAX_SG_DESC_CNT 256 /* Maximum descriptors per sgl */
|
||||
#define FNIC_SG_DESC_ALIGN 16 /* Descriptor address alignment */
|
||||
|
||||
#define NVME_STAT_ERROR 0x2
|
||||
#define NVME_STAT_TASK_SET_FULL 0x3
|
||||
|
||||
struct host_sg_desc {
|
||||
__le64 addr;
|
||||
__le32 len;
|
||||
@@ -39,6 +45,7 @@ enum fnic_ioreq_state {
|
||||
FNIC_IOREQ_ABTS_PENDING,
|
||||
FNIC_IOREQ_ABTS_COMPLETE,
|
||||
FNIC_IOREQ_CMD_COMPLETE,
|
||||
FNIC_IOREQ_RESET_TERM,
|
||||
};
|
||||
|
||||
struct fnic_io_req {
|
||||
@@ -50,12 +57,27 @@ struct fnic_io_req {
|
||||
dma_addr_t sgl_list_pa; /* dma address for sgl list */
|
||||
u16 sgl_cnt;
|
||||
u8 sgl_type; /* device DMA descriptor list type */
|
||||
u8 sgl_mapped:1; /* set when sgl_list_pa is a valid DMA mapping */
|
||||
u8 io_completed:1; /* set to 1 when fw completes IO */
|
||||
u32 port_id; /* remote port DID */
|
||||
unsigned long start_time; /* in jiffies */
|
||||
u32 tag;
|
||||
enum fnic_ioreq_state cmd_state;
|
||||
u32 cmd_flags;
|
||||
u32 abts_state;
|
||||
struct completion *abts_done; /* completion for abts */
|
||||
struct completion *dr_done; /* completion for device reset */
|
||||
unsigned int tag;
|
||||
struct scsi_cmnd *sc; /* midlayer's cmd pointer */
|
||||
|
||||
struct vnic_wq_copy *wq;
|
||||
struct llist_node nvfnic_io_cmpl;
|
||||
struct nvmefc_fcp_req *fcp_req;
|
||||
void (*done)(struct fnic_io_req *io_req);
|
||||
unsigned long waitq_start_time; /* in jiffies */
|
||||
|
||||
struct timer_list admin_io_timer;
|
||||
uint32_t status;
|
||||
struct fnic_tag_t *tag_data;
|
||||
struct fnic_io_event_s io_evt;
|
||||
};
|
||||
#endif /* _FNIC_IO_H_ */
|
||||
|
||||
@@ -222,7 +222,7 @@ int fnic_request_intr(struct fnic *fnic)
|
||||
fnic->msix[i].devname,
|
||||
fnic->msix[i].devid);
|
||||
if (err) {
|
||||
FNIC_ISR_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_ERR, fnic,
|
||||
"request_irq failed with error: %d\n",
|
||||
err);
|
||||
fnic_free_intr(fnic);
|
||||
@@ -250,10 +250,10 @@ int fnic_set_intr_mode_msix(struct fnic *fnic)
|
||||
* We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs
|
||||
* (last INTR is used for WQ/RQ errors and notification area)
|
||||
*/
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic,
|
||||
"rq-array size: %d wq-array size: %d copy-wq array size: %d\n",
|
||||
n, m, o);
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic,
|
||||
"rq_count: %d raw_wq_count: %d wq_copy_count: %d cq_count: %d\n",
|
||||
fnic->rq_count, fnic->raw_wq_count,
|
||||
fnic->wq_copy_count, fnic->cq_count);
|
||||
@@ -265,17 +265,17 @@ int fnic_set_intr_mode_msix(struct fnic *fnic)
|
||||
|
||||
vec_count = pci_alloc_irq_vectors(fnic->pdev, min_irqs, vecs,
|
||||
PCI_IRQ_MSIX | PCI_IRQ_AFFINITY);
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic,
|
||||
"allocated %d MSI-X vectors\n",
|
||||
vec_count);
|
||||
|
||||
if (vec_count > 0) {
|
||||
if (vec_count < vecs) {
|
||||
FNIC_ISR_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_ERR, fnic,
|
||||
"interrupts number mismatch: vec_count: %d vecs: %d\n",
|
||||
vec_count, vecs);
|
||||
if (vec_count < min_irqs) {
|
||||
FNIC_ISR_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_ERR, fnic,
|
||||
"no interrupts for copy wq\n");
|
||||
return 1;
|
||||
}
|
||||
@@ -287,7 +287,7 @@ int fnic_set_intr_mode_msix(struct fnic *fnic)
|
||||
fnic->wq_copy_count = vec_count - n - m - 1;
|
||||
fnic->wq_count = fnic->raw_wq_count + fnic->wq_copy_count;
|
||||
if (fnic->cq_count != vec_count - 1) {
|
||||
FNIC_ISR_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_ERR, fnic,
|
||||
"CQ count: %d does not match MSI-X vector count: %d\n",
|
||||
fnic->cq_count, vec_count);
|
||||
fnic->cq_count = vec_count - 1;
|
||||
@@ -295,23 +295,23 @@ int fnic_set_intr_mode_msix(struct fnic *fnic)
|
||||
fnic->intr_count = vec_count;
|
||||
fnic->err_intr_offset = fnic->rq_count + fnic->wq_count;
|
||||
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic,
|
||||
"rq_count: %d raw_wq_count: %d copy_wq_base: %d\n",
|
||||
fnic->rq_count,
|
||||
fnic->raw_wq_count, fnic->copy_wq_base);
|
||||
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic,
|
||||
"wq_copy_count: %d wq_count: %d cq_count: %d\n",
|
||||
fnic->wq_copy_count,
|
||||
fnic->wq_count, fnic->cq_count);
|
||||
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
"intr_count: %d err_intr_offset: %u",
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic,
|
||||
"intr_count: %d err_intr_offset: %u\n",
|
||||
fnic->intr_count,
|
||||
fnic->err_intr_offset);
|
||||
|
||||
vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSIX);
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_INFO, fnic,
|
||||
"fnic using MSI-X\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -351,7 +351,7 @@ int fnic_set_intr_mode(struct fnic *fnic)
|
||||
fnic->intr_count = 1;
|
||||
fnic->err_intr_offset = 0;
|
||||
|
||||
FNIC_ISR_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_DEBUG, fnic,
|
||||
"Using MSI Interrupts\n");
|
||||
vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI);
|
||||
|
||||
@@ -377,7 +377,7 @@ int fnic_set_intr_mode(struct fnic *fnic)
|
||||
fnic->cq_count = 3;
|
||||
fnic->intr_count = 3;
|
||||
|
||||
FNIC_ISR_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_ISR_DBG(KERN_DEBUG, fnic,
|
||||
"Using Legacy Interrupts\n");
|
||||
vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX);
|
||||
|
||||
|
||||
+171
-43
@@ -42,12 +42,12 @@ static struct kmem_cache *fdls_frame_cache;
|
||||
static struct kmem_cache *fdls_frame_elem_cache;
|
||||
static struct kmem_cache *fdls_frame_recv_cache;
|
||||
static LIST_HEAD(fnic_list);
|
||||
static DEFINE_SPINLOCK(fnic_list_lock);
|
||||
static DEFINE_IDA(fnic_ida);
|
||||
|
||||
struct work_struct reset_fnic_work;
|
||||
LIST_HEAD(reset_fnic_list);
|
||||
DEFINE_SPINLOCK(reset_fnic_list_lock);
|
||||
DEFINE_SPINLOCK(fnic_list_lock);
|
||||
|
||||
/* Supported devices by fnic module */
|
||||
static const struct pci_device_id fnic_id_table[] = {
|
||||
@@ -89,6 +89,15 @@ module_param(fnic_fc_trace_max_pages, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(fnic_fc_trace_max_pages,
|
||||
"Total allocated memory pages for fc trace buffer");
|
||||
|
||||
unsigned int nvme_dev_loss_tmo = 30;
|
||||
module_param_named(nvme_dev_loss_tmo, nvme_dev_loss_tmo, uint, 0644);
|
||||
MODULE_PARM_DESC(nvme_dev_loss_tmo, "configurable NVME dev loss timeout");
|
||||
|
||||
unsigned int nvme_max_ios_to_process = 16;
|
||||
module_param(nvme_max_ios_to_process, uint, 0644);
|
||||
MODULE_PARM_DESC(nvme_max_ios_to_process,
|
||||
"Maximum number of NVME IOs to process per work queue");
|
||||
|
||||
static unsigned int fnic_max_qdepth = FNIC_DFLT_QUEUE_DEPTH;
|
||||
module_param(fnic_max_qdepth, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(fnic_max_qdepth, "Queue depth to report for each LUN");
|
||||
@@ -100,6 +109,7 @@ MODULE_PARM_DESC(pc_rscn_handling_feature_flag,
|
||||
|
||||
struct workqueue_struct *reset_fnic_work_queue;
|
||||
struct workqueue_struct *fnic_fip_queue;
|
||||
struct workqueue_struct *fnic_cmpl_queue;
|
||||
|
||||
static int fnic_sdev_init(struct scsi_device *sdev)
|
||||
{
|
||||
@@ -185,7 +195,7 @@ static void fnic_get_host_speed(struct Scsi_Host *shost)
|
||||
u32 port_speed = vnic_dev_port_speed(fnic->vdev);
|
||||
struct fnic_stats *fnic_stats = &fnic->fnic_stats;
|
||||
|
||||
FNIC_MAIN_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_MAIN_DBG(KERN_INFO, fnic,
|
||||
"port_speed: %d Mbps", port_speed);
|
||||
atomic64_set(&fnic_stats->misc_stats.port_speed_in_mbps, port_speed);
|
||||
|
||||
@@ -235,7 +245,7 @@ static void fnic_get_host_speed(struct Scsi_Host *shost)
|
||||
fc_host_speed(shost) = FC_PORTSPEED_128GBIT;
|
||||
break;
|
||||
default:
|
||||
FNIC_MAIN_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_MAIN_DBG(KERN_INFO, fnic,
|
||||
"Unknown FC speed: %d Mbps", port_speed);
|
||||
fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
|
||||
break;
|
||||
@@ -261,7 +271,7 @@ static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host)
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
|
||||
if (ret) {
|
||||
FNIC_MAIN_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_MAIN_DBG(KERN_DEBUG, fnic,
|
||||
"fnic: Get vnic stats failed: 0x%x", ret);
|
||||
return stats;
|
||||
}
|
||||
@@ -287,64 +297,66 @@ static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host)
|
||||
void fnic_dump_fchost_stats(struct Scsi_Host *host,
|
||||
struct fc_host_statistics *stats)
|
||||
{
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
struct fnic *fnic = *((struct fnic **) shost_priv(host));
|
||||
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: seconds since last reset = %llu\n",
|
||||
stats->seconds_since_last_reset);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: tx frames = %llu\n",
|
||||
stats->tx_frames);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: tx words = %llu\n",
|
||||
stats->tx_words);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: rx frames = %llu\n",
|
||||
stats->rx_frames);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: rx words = %llu\n",
|
||||
stats->rx_words);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: lip count = %llu\n",
|
||||
stats->lip_count);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: nos count = %llu\n",
|
||||
stats->nos_count);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: error frames = %llu\n",
|
||||
stats->error_frames);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: dumped frames = %llu\n",
|
||||
stats->dumped_frames);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: link failure count = %llu\n",
|
||||
stats->link_failure_count);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: loss of sync count = %llu\n",
|
||||
stats->loss_of_sync_count);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: loss of signal count = %llu\n",
|
||||
stats->loss_of_signal_count);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: prim seq protocol err count = %llu\n",
|
||||
stats->prim_seq_protocol_err_count);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: invalid tx word count= %llu\n",
|
||||
stats->invalid_tx_word_count);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: invalid crc count = %llu\n",
|
||||
stats->invalid_crc_count);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: fcp input requests = %llu\n",
|
||||
stats->fcp_input_requests);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: fcp output requests = %llu\n",
|
||||
stats->fcp_output_requests);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: fcp control requests = %llu\n",
|
||||
stats->fcp_control_requests);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: fcp input megabytes = %llu\n",
|
||||
stats->fcp_input_megabytes);
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, host,
|
||||
FNIC_MAIN_NOTE(KERN_NOTICE, fnic,
|
||||
"fnic: fcp output megabytes = %llu\n",
|
||||
stats->fcp_output_megabytes);
|
||||
return;
|
||||
@@ -370,7 +382,7 @@ static void fnic_reset_host_stats(struct Scsi_Host *host)
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
|
||||
if (ret) {
|
||||
FNIC_MAIN_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_MAIN_DBG(KERN_DEBUG, fnic,
|
||||
"fnic: Reset vnic stats failed"
|
||||
" 0x%x", ret);
|
||||
return;
|
||||
@@ -547,6 +559,9 @@ static int fnic_cleanup(struct fnic *fnic)
|
||||
vnic_wq_copy_clean(&fnic->hw_copy_wq[i],
|
||||
fnic_wq_copy_cleanup_handler);
|
||||
|
||||
if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_flush_nvme_io_list(fnic);
|
||||
|
||||
for (i = 0; i < fnic->cq_count; i++)
|
||||
vnic_cq_clean(&fnic->cq[i]);
|
||||
for (i = 0; i < fnic->intr_count; i++)
|
||||
@@ -676,6 +691,59 @@ static int fnic_scsi_drv_init(struct fnic *fnic)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fnic_nvme_drv_init(struct fnic *fnic)
|
||||
{
|
||||
int ret;
|
||||
int hwq;
|
||||
|
||||
fnic->fnic_max_tag_id = NVFNIC_FCPIO_TAG_POOL_SZ;
|
||||
|
||||
for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) {
|
||||
fnic->sw_copy_wq[hwq].ioreq_table_size = fnic->fnic_max_tag_id;
|
||||
fnic->sw_copy_wq[hwq].io_req_table =
|
||||
kzalloc((fnic->sw_copy_wq[hwq].ioreq_table_size + 1) *
|
||||
sizeof(struct fnic_io_req *), GFP_KERNEL);
|
||||
|
||||
if (!fnic->sw_copy_wq[hwq].io_req_table) {
|
||||
fnic_free_ioreq_tables_mq(fnic);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&fnic->pdev->dev, "fnic copy wqs: %d, Q0 ioreq table size: %d\n",
|
||||
fnic->wq_copy_count, fnic->sw_copy_wq[0].ioreq_table_size);
|
||||
|
||||
if (sbitmap_init_node(&fnic->nvfnic_tag_map, NVFNIC_FCPIO_TAG_POOL_SZ,
|
||||
-1, GFP_KERNEL, NUMA_NO_NODE, false, true)) {
|
||||
dev_err(&fnic->pdev->dev,
|
||||
"Unable to allocate tag pool\n");
|
||||
ret = -ENOMEM;
|
||||
goto out_free_ioreq_tables;
|
||||
}
|
||||
|
||||
fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache);
|
||||
if (!fnic->io_req_pool) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_sbitmap;
|
||||
}
|
||||
|
||||
init_llist_head(&fnic->nvme_io_event_llist);
|
||||
INIT_WORK(&fnic->nvme_io_cmpl_work, nvfnic_nvme_iodone_work);
|
||||
|
||||
ret = nvfnic_add_lport(fnic);
|
||||
if (ret)
|
||||
goto out_free_req_pool;
|
||||
|
||||
return 0;
|
||||
out_free_req_pool:
|
||||
mempool_destroy(fnic->io_req_pool);
|
||||
out_free_sbitmap:
|
||||
sbitmap_free(&fnic->nvfnic_tag_map);
|
||||
out_free_ioreq_tables:
|
||||
fnic_free_ioreq_tables_mq(fnic);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void fnic_mq_map_queues_cpus(struct Scsi_Host *host)
|
||||
{
|
||||
struct fnic *fnic = *((struct fnic **) shost_priv(host));
|
||||
@@ -684,16 +752,16 @@ void fnic_mq_map_queues_cpus(struct Scsi_Host *host)
|
||||
struct blk_mq_queue_map *qmap = &host->tag_set.map[HCTX_TYPE_DEFAULT];
|
||||
|
||||
if (intr_mode == VNIC_DEV_INTR_MODE_MSI || intr_mode == VNIC_DEV_INTR_MODE_INTX) {
|
||||
FNIC_MAIN_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_MAIN_DBG(KERN_ERR, fnic,
|
||||
"intr_mode is not msix\n");
|
||||
return;
|
||||
}
|
||||
|
||||
FNIC_MAIN_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_MAIN_DBG(KERN_INFO, fnic,
|
||||
"qmap->nr_queues: %d\n", qmap->nr_queues);
|
||||
|
||||
if (l_pdev == NULL) {
|
||||
FNIC_MAIN_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_MAIN_DBG(KERN_ERR, fnic,
|
||||
"l_pdev is null\n");
|
||||
return;
|
||||
}
|
||||
@@ -842,7 +910,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
goto err_out_fnic_get_config;
|
||||
}
|
||||
|
||||
switch (fnic->config.flags & 0xff0) {
|
||||
switch (fnic->config.flags & FNIC_ROLE_CONFIG_MASK) {
|
||||
case VFCF_FC_INITIATOR:
|
||||
{
|
||||
host =
|
||||
@@ -861,8 +929,28 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
fnic->fnic_num);
|
||||
}
|
||||
break;
|
||||
case VFCF_FC_TARGET:
|
||||
dev_info(&fnic->pdev->dev,
|
||||
"fnic: %d is scsi target\n",
|
||||
fnic->fnic_num);
|
||||
err = -EOPNOTSUPP;
|
||||
goto err_out_fnic_role;
|
||||
case VFCF_FC_NVME_INITIATOR:
|
||||
fnic_nvmef_debugfs_init(fnic);
|
||||
fnic->role = FNIC_ROLE_NVME_INITIATOR;
|
||||
dev_info(&fnic->pdev->dev, "fnic: %d is NVME initiator\n",
|
||||
fnic->fnic_num);
|
||||
break;
|
||||
case VFCF_FC_NVME_TARGET:
|
||||
dev_info(&fnic->pdev->dev,
|
||||
"fnic: %d is NVME target\n",
|
||||
fnic->fnic_num);
|
||||
err = -EOPNOTSUPP;
|
||||
goto err_out_fnic_role;
|
||||
default:
|
||||
dev_info(&fnic->pdev->dev, "fnic: %d has no role defined\n", fnic->fnic_num);
|
||||
dev_info(&fnic->pdev->dev,
|
||||
"fnic: %d has no role defined (0x%x)\n",
|
||||
fnic->fnic_num, fnic->config.flags & FNIC_ROLE_CONFIG_MASK);
|
||||
err = -EINVAL;
|
||||
goto err_out_fnic_role;
|
||||
}
|
||||
@@ -995,11 +1083,16 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
iport->max_flogi_retries = fnic->config.flogi_retries;
|
||||
iport->max_plogi_retries = fnic->config.plogi_retries;
|
||||
iport->plogi_timeout = fnic->config.plogi_timeout;
|
||||
iport->service_params =
|
||||
(FNIC_FCP_SP_INITIATOR | FNIC_FCP_SP_RD_XRDY_DIS |
|
||||
FNIC_FCP_SP_CONF_CMPL);
|
||||
if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR)
|
||||
iport->service_params |= FNIC_FCP_SP_RETRY;
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic)) {
|
||||
iport->service_params = (FNIC_FCP_SP_INITIATOR |
|
||||
FNIC_FCP_SP_RD_XRDY_DIS | FNIC_FCP_SP_CONF_CMPL);
|
||||
if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR)
|
||||
iport->service_params |= FNIC_FCP_SP_RETRY;
|
||||
} else if (IS_FNIC_NVME_INITIATOR(fnic)) {
|
||||
iport->service_params = (FNIC_NVME_SP_INITIATOR);
|
||||
if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR)
|
||||
iport->service_params |= FNIC_NVME_SP_SLER;
|
||||
}
|
||||
|
||||
iport->boot_time = jiffies;
|
||||
iport->e_d_tov = fnic->config.ed_tov;
|
||||
@@ -1031,6 +1124,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
INIT_LIST_HEAD(&fnic->frame_queue);
|
||||
INIT_LIST_HEAD(&fnic->tx_queue);
|
||||
INIT_LIST_HEAD(&fnic->tport_event_list);
|
||||
init_llist_head(&fnic->nvme_io_event_llist);
|
||||
|
||||
INIT_DELAYED_WORK(&iport->oxid_pool.schedule_oxid_free_retry,
|
||||
fdls_schedule_oxid_free_retry_work);
|
||||
@@ -1061,9 +1155,15 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
|
||||
fnic_fdls_init(fnic, (fnic->config.flags & VFCF_FIP_CAPABLE));
|
||||
|
||||
err = fnic_scsi_drv_init(fnic);
|
||||
if (err)
|
||||
goto err_out_scsi_drv_init;
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic)) {
|
||||
err = fnic_scsi_drv_init(fnic);
|
||||
if (err)
|
||||
goto err_out_scsi_drv_init;
|
||||
} else if (IS_FNIC_NVME_INITIATOR(fnic)) {
|
||||
err = fnic_nvme_drv_init(fnic);
|
||||
if (err)
|
||||
goto err_out_nvme_drv_init;
|
||||
}
|
||||
|
||||
err = fnic_stats_debugfs_init(fnic);
|
||||
if (err) {
|
||||
@@ -1083,7 +1183,9 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
err_out_free_stats_debugfs:
|
||||
fnic_stats_debugfs_remove(fnic);
|
||||
fnic_free_ioreq_tables_mq(fnic);
|
||||
scsi_remove_host(fnic->host);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
scsi_remove_host(fnic->host);
|
||||
err_out_nvme_drv_init:
|
||||
err_out_scsi_drv_init:
|
||||
fnic_free_intr(fnic);
|
||||
err_out_fnic_request_intr:
|
||||
@@ -1109,7 +1211,10 @@ err_out_free_resources:
|
||||
err_out_fnic_alloc_vnic_res:
|
||||
fnic_clear_intr_mode(fnic);
|
||||
err_out_fnic_set_intr_mode:
|
||||
scsi_host_put(fnic->host);
|
||||
if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
fnic_nvmef_debugfs_remove(fnic);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
scsi_host_put(fnic->host);
|
||||
err_out_fnic_role:
|
||||
err_out_scsi_host_alloc:
|
||||
err_out_fnic_get_config:
|
||||
@@ -1158,7 +1263,10 @@ static void fnic_remove(struct pci_dev *pdev)
|
||||
*/
|
||||
flush_workqueue(fnic_event_queue);
|
||||
|
||||
fnic_scsi_unload(fnic);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
fnic_scsi_unload(fnic);
|
||||
else if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_nvme_unload(fnic);
|
||||
|
||||
if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI)
|
||||
timer_delete_sync(&fnic->notify_timer);
|
||||
@@ -1175,6 +1283,7 @@ static void fnic_remove(struct pci_dev *pdev)
|
||||
if ((fnic_fdmi_support == 1) && (fnic->iport.fabric.fdmi_pending > 0))
|
||||
timer_delete_sync(&fnic->iport.fabric.fdmi_timer);
|
||||
|
||||
fnic_nvmef_debugfs_remove(fnic);
|
||||
fnic_stats_debugfs_remove(fnic);
|
||||
|
||||
/*
|
||||
@@ -1184,6 +1293,11 @@ static void fnic_remove(struct pci_dev *pdev)
|
||||
*/
|
||||
fnic_cleanup(fnic);
|
||||
|
||||
if (IS_FNIC_NVME_INITIATOR(fnic)) {
|
||||
sbitmap_free(&fnic->nvfnic_tag_map);
|
||||
fnic_free_ioreq_tables_mq(fnic);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&fnic_list_lock, flags);
|
||||
list_del(&fnic->list);
|
||||
spin_unlock_irqrestore(&fnic_list_lock, flags);
|
||||
@@ -1202,8 +1316,10 @@ static void fnic_remove(struct pci_dev *pdev)
|
||||
pci_disable_device(pdev);
|
||||
pci_set_drvdata(pdev, NULL);
|
||||
ida_free(&fnic_ida, fnic->fnic_num);
|
||||
fnic_scsi_unload_cleanup(fnic);
|
||||
scsi_host_put(fnic->host);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic)) {
|
||||
fnic_scsi_unload_cleanup(fnic);
|
||||
scsi_host_put(fnic->host);
|
||||
}
|
||||
kfree(fnic);
|
||||
}
|
||||
|
||||
@@ -1323,6 +1439,15 @@ static int __init fnic_init_module(void)
|
||||
goto err_create_fip_workq;
|
||||
}
|
||||
|
||||
fnic_cmpl_queue =
|
||||
alloc_workqueue("fnic_cmpl_wq",
|
||||
WQ_PERCPU | WQ_HIGHPRI | WQ_MEM_RECLAIM, 0);
|
||||
if (!fnic_cmpl_queue) {
|
||||
pr_err("fnic completion work queue create failed\n");
|
||||
err = -ENOMEM;
|
||||
goto err_create_cmpl_workq;
|
||||
}
|
||||
|
||||
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON) {
|
||||
reset_fnic_work_queue =
|
||||
create_singlethread_workqueue("reset_fnic_work_queue");
|
||||
@@ -1354,6 +1479,8 @@ static int __init fnic_init_module(void)
|
||||
err_pci_register:
|
||||
fc_release_transport(fnic_fc_transport);
|
||||
err_fc_transport:
|
||||
destroy_workqueue(fnic_cmpl_queue);
|
||||
err_create_cmpl_workq:
|
||||
destroy_workqueue(fnic_fip_queue);
|
||||
err_create_fip_workq:
|
||||
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON)
|
||||
@@ -1382,6 +1509,7 @@ err_create_fnic_sgl_slab_dflt:
|
||||
static void __exit fnic_cleanup_module(void)
|
||||
{
|
||||
pci_unregister_driver(&fnic_driver);
|
||||
destroy_workqueue(fnic_cmpl_queue);
|
||||
destroy_workqueue(fnic_event_queue);
|
||||
|
||||
if (pc_rscn_handling_feature_flag == PC_RSCN_HANDLING_FEATURE_ON)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,214 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright 2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright 2007 Nuova Systems, Inc. All rights reserved.
|
||||
*/
|
||||
#ifndef _FNIC_NVME_H
|
||||
#define _FNIC_NVME_H
|
||||
|
||||
#include "fdls_fc.h"
|
||||
#include "fnic_fdls.h"
|
||||
|
||||
#define FNIC_NVME_TPORT_REMOVE_WAIT (5 * 1000)
|
||||
#define FNIC_NVME_TPORT_LIST_EMPTY_WAIT (FNIC_NVME_TPORT_REMOVE_WAIT * 2)
|
||||
#define FNIC_TPORT_CLEANUP_WAIT_COUNT 8
|
||||
#define FNIC_NVME_LPORT_REMOVE_WAIT (2 * 60 * 1000)
|
||||
|
||||
#define FNIC_LS_REQ_FLAGS_NONE 0x0
|
||||
#define FNIC_LS_REQ_FLAGS_ABORTED 0x1
|
||||
#define FNIC_LS_REQ_FLAGS_DONE 0x2
|
||||
#define FNIC_LS_REQ_ABORT_COMPLETED 0x4
|
||||
#define FNIC_STATUS_LS_REQ_ABORTED 0x1
|
||||
|
||||
#define FNIC_LS_REQ_MIN_TMO_SECS (2)
|
||||
#define FNIC_LS_REQ_MAX_TMO_SECS (5)
|
||||
#define FNIC_NVME_ADMIN_IO_TIMEOUT 30000 /* mSec */
|
||||
#define FNIC_NVME_NO_FREE_TAG (0xFFFF)
|
||||
|
||||
#define FNIC_LS_REQ_TMO_MSECS(tmo) (((tmo >= FNIC_LS_REQ_MIN_TMO_SECS) && \
|
||||
(tmo <= FNIC_LS_REQ_MAX_TMO_SECS)) ? \
|
||||
(tmo * 1000) : (FNIC_LS_REQ_MIN_TMO_SECS * 1000))
|
||||
|
||||
#define IS_ADMIN_IO(_io_req) \
|
||||
(NVME_CMD_FLAGS(_io_req) & FNIC_NVME_ADMIN_IO_TIMER_PENDING)
|
||||
|
||||
extern unsigned int nvme_max_ios_to_process;
|
||||
extern unsigned int nvme_dev_loss_tmo;
|
||||
extern spinlock_t fnic_list_lock;
|
||||
|
||||
enum nvfnic_lsreq_state_e {
|
||||
FNIC_LS_REQ_CMD_INIT = 0,
|
||||
FNIC_LS_REQ_CMD_PENDING,
|
||||
FNIC_LS_REQ_CMD_ABTS_PENDING,
|
||||
FNIC_LS_REQ_CMD_COMPLETE,
|
||||
FNIC_LS_REQ_ABTS_COMPLETE,
|
||||
FNIC_LS_REQ_CMD_ABTS_STARTED,
|
||||
};
|
||||
|
||||
struct fnic_nvme_tag {
|
||||
struct list_head free_list;
|
||||
int tag_id;
|
||||
};
|
||||
|
||||
struct nvfnic_ls_req {
|
||||
struct list_head list;
|
||||
struct nvmefc_ls_req *ls_req;
|
||||
uint16_t oxid;
|
||||
struct timer_list ls_req_timer;
|
||||
struct fnic *fnic;
|
||||
struct fnic_tport_s *tport;
|
||||
int state;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
#if IS_REACHABLE(CONFIG_NVME_FC)
|
||||
int nvfnic_nvme_io_done_handler(void *arg);
|
||||
struct fnic_io_req *nvfnic_find_io_req_by_tag(struct fnic *fnic, uint16_t tag);
|
||||
void nvfnic_reset_fcpio_tag_pool(struct fnic_iport_s *iport);
|
||||
int nvfnic_add_lport(struct fnic *fnic);
|
||||
void nvfnic_fcpio_abort(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
void *hw_queue_handle, struct nvmefc_fcp_req *fcp_req);
|
||||
void nvfnic_remote_port_delete(struct nvme_fc_remote_port *rport);
|
||||
void nvfnic_local_port_delete(struct nvme_fc_local_port *lport);
|
||||
int nvfnic_dma_map_sgl(struct fnic *fnic, struct fnic_io_req *io_req,
|
||||
int sg_count);
|
||||
void nvfnic_dma_unmap_sgl(struct fnic *fnic, struct fnic_io_req *io_req);
|
||||
int nvfnic_get_sg_count(struct fnic_io_req *io_req);
|
||||
void nvfnic_release_nvme_ioreq_buf(struct fnic_iport_s *iport,
|
||||
struct fnic_io_req *io_req);
|
||||
void nvfnic_dump_nvcmd(struct fnic_io_req *io_req, uint8_t flags);
|
||||
bool _cleanup_tport_io(struct sbitmap *map, unsigned int tag, void *data);
|
||||
void nvfnic_flush_nvme_io_list(struct fnic *fnic);
|
||||
void nvfnic_fcpio_cmpl(struct fnic_io_req *io_req);
|
||||
bool nvfnic_transport_ready(struct fnic_iport_s *iport,
|
||||
struct fnic_tport_s *tport);
|
||||
int nvfnic_alloc_fcpio_tag(struct fnic_iport_s *iport,
|
||||
struct fnic_io_req *io_req);
|
||||
int nvfnic_queuecommand(struct fnic_io_req *io_req);
|
||||
void nvfnic_free_fcpio_tag(struct fnic_iport_s *iport,
|
||||
struct fnic_io_req *io_req);
|
||||
void nvfnic_delete_lport(struct fnic_iport_s *iport);
|
||||
int nvfnic_add_tport(struct fnic *fnic, struct fnic_tport_s *tport,
|
||||
unsigned long flags);
|
||||
void nvfnic_cleanup_all_nvme_ios(struct fnic *fnic);
|
||||
void nvfnic_delete_tport_work(struct work_struct *work);
|
||||
void nvfnic_delete_tport(struct fnic_iport_s *iport,
|
||||
struct fnic_tport_s *tport, unsigned long flags);
|
||||
void nvfnic_fcpio_nvme_fast_cmpl_handler(struct fnic *fnic,
|
||||
struct fcpio_fw_req *desc);
|
||||
void nvfnic_ls_rsp_recv(struct fnic_iport_s *iport,
|
||||
struct fc_frame_header *fchdr, int len);
|
||||
void nvfnic_process_ls_abts_rsp(struct fnic_iport_s *iport,
|
||||
struct fc_frame_header *fchdr);
|
||||
void nvfnic_admin_io_timeout(struct timer_list *t);
|
||||
void nvfnic_fcpio_nvme_itmf_cmpl_handler(struct fnic *fnic,
|
||||
struct fcpio_fw_req *desc);
|
||||
void nvfnic_nvme_zero_devloss_tports(struct fnic *fnic);
|
||||
bool nvfnic_queue_abort_io_req(struct fnic *fnic, int tag, u32 task_req,
|
||||
struct fnic_io_req *io_req);
|
||||
void nvfnic_ls_req_abort(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_ls_req *lsreq);
|
||||
int nvfnic_create_queue(struct nvme_fc_local_port *lport, unsigned int idx,
|
||||
u16 size, void **handle);
|
||||
int nvfnic_ls_req_send(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_ls_req *ls_req);
|
||||
void nvfnic_ls_req_timeout(struct timer_list *t);
|
||||
uint16_t nvfnic_alloc_ls_req_oxid(struct fnic_iport_s *iport);
|
||||
struct nvfnic_ls_req *nvfnic_find_ls_req(struct fnic_tport_s *tport,
|
||||
uint16_t oxid);
|
||||
void nvfnic_terminate_tport_ios(struct fnic *fnic, struct fnic_tport_s *tport);
|
||||
bool _terminate_tport_ios(struct sbitmap *map, unsigned int tag, void *data);
|
||||
bool _cleanup_all_nvme_io(struct sbitmap *map, unsigned int tag, void *data);
|
||||
void nvfnic_cleanup_all_nvme_ios(struct fnic *fnic);
|
||||
int nvfnic_fcpio_send(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport, void *hw_queue_handle,
|
||||
struct nvmefc_fcp_req *fcp_req);
|
||||
void nvfnic_fcpio_ersp_cmpl_handler(struct fnic *fnic,
|
||||
struct fcpio_fw_req *desc, int sw_flag);
|
||||
void nvfnic_terminate_tport_ls_reqs(struct fnic *fnic,
|
||||
struct fnic_tport_s *tport);
|
||||
void nvfnic_terminate_tport_admin_ios(struct fnic *fnic,
|
||||
struct fnic_tport_s *tport);
|
||||
void nvfnic_cleanup_tport_io(struct fnic *fnic, struct fnic_tport_s *tport);
|
||||
void nvfnic_nvme_unload(struct fnic *fnic);
|
||||
int nvfnic_get_nvmef_info(struct fnic *fnic, struct fnic_nvmef_info *info);
|
||||
void nvfnic_exch_reset(struct fnic_iport_s *iport, struct fnic_tport_s *tport);
|
||||
void nvfnic_nvme_iodone_work(struct work_struct *work);
|
||||
#else
|
||||
static inline int nvfnic_add_lport(struct fnic *fnic)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline void nvfnic_nvme_unload(struct fnic *fnic)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_flush_nvme_io_list(struct fnic *fnic)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_nvme_iodone_work(struct work_struct *work)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_exch_reset(struct fnic_iport_s *iport,
|
||||
struct fnic_tport_s *tport)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_process_ls_abts_rsp(struct fnic_iport_s *iport,
|
||||
struct fc_frame_header *fchdr)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_ls_rsp_recv(struct fnic_iport_s *iport,
|
||||
struct fc_frame_header *fchdr, int len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int nvfnic_add_tport(struct fnic *fnic,
|
||||
struct fnic_tport_s *tport,
|
||||
unsigned long flags)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void nvfnic_delete_tport(struct fnic_iport_s *iport,
|
||||
struct fnic_tport_s *tport,
|
||||
unsigned long flags)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_cleanup_all_nvme_ios(struct fnic *fnic)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_fcpio_nvme_fast_cmpl_handler(struct fnic *fnic,
|
||||
struct fcpio_fw_req *desc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_fcpio_ersp_cmpl_handler(struct fnic *fnic,
|
||||
struct fcpio_fw_req *desc,
|
||||
int sw_flag)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void nvfnic_fcpio_nvme_itmf_cmpl_handler(struct fnic *fnic,
|
||||
struct fcpio_fw_req *desc)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int nvfnic_get_nvmef_info(struct fnic *fnic,
|
||||
struct fnic_nvmef_info *info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern const char *fnic_fcpio_status_to_str(unsigned int status);
|
||||
#endif /* _FNIC_NVME_H */
|
||||
@@ -22,6 +22,7 @@
|
||||
int fnic_get_vnic_config(struct fnic *fnic)
|
||||
{
|
||||
struct vnic_fc_config *c = &fnic->config;
|
||||
u32 role;
|
||||
int err;
|
||||
|
||||
#define GET_CONFIG(m) \
|
||||
@@ -56,11 +57,35 @@ int fnic_get_vnic_config(struct fnic *fnic)
|
||||
GET_CONFIG(port_down_io_retries);
|
||||
GET_CONFIG(luns_per_tgt);
|
||||
GET_CONFIG(intr_mode);
|
||||
GET_CONFIG(lun_queue_depth);
|
||||
GET_CONFIG(io_timeout_retry);
|
||||
GET_CONFIG(wq_copy_count);
|
||||
|
||||
if ((c->flags & (VFCF_FC_INITIATOR)) == 0) {
|
||||
dev_info(&fnic->pdev->dev, "vNIC role not defined (def role: FC Init)\n");
|
||||
role = c->flags & FNIC_ROLE_CONFIG_MASK;
|
||||
switch (role) {
|
||||
case 0:
|
||||
dev_info(&fnic->pdev->dev,
|
||||
"vNIC role not defined (def role: FC Init)\n");
|
||||
c->flags |= VFCF_FC_INITIATOR;
|
||||
break;
|
||||
case VFCF_FC_INITIATOR:
|
||||
case VFCF_FC_NVME_INITIATOR:
|
||||
break;
|
||||
case VFCF_FC_TARGET:
|
||||
dev_info(&fnic->pdev->dev,
|
||||
"vNIC role is FC Target (unsupported)\n");
|
||||
break;
|
||||
case VFCF_FC_NVME_TARGET:
|
||||
dev_info(&fnic->pdev->dev,
|
||||
"vNIC role is FC-NVMe Target (unsupported)\n");
|
||||
break;
|
||||
default:
|
||||
dev_info(&fnic->pdev->dev,
|
||||
"vNIC role not supported (0x%x), defaulting to FC Init\n",
|
||||
role);
|
||||
c->flags &= ~FNIC_ROLE_CONFIG_MASK;
|
||||
c->flags |= VFCF_FC_INITIATOR;
|
||||
break;
|
||||
}
|
||||
|
||||
c->wq_enet_desc_count =
|
||||
@@ -163,6 +188,8 @@ int fnic_get_vnic_config(struct fnic *fnic)
|
||||
c->port_down_io_retries, c->port_down_timeout);
|
||||
dev_info(&fnic->pdev->dev, "fNIC wq_copy_count: %d\n", c->wq_copy_count);
|
||||
dev_info(&fnic->pdev->dev, "fNIC intr mode: %d\n", c->intr_mode);
|
||||
dev_info(&fnic->pdev->dev, "fNIC role flags: 0x%x\n",
|
||||
(c->flags & FNIC_ROLE_CONFIG_MASK));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -126,7 +126,8 @@ static inline void fnic_queue_wq_copy_desc_itmf(struct vnic_wq_copy *wq,
|
||||
desc->u.itmf.tm_req = tm_req; /* SCSI Task Management request */
|
||||
desc->u.itmf.t_tag = tm_id; /* tag of fcpio to be aborted */
|
||||
desc->u.itmf._resvd = 0;
|
||||
memcpy(desc->u.itmf.lun, lun, LUN_ADDRESS); /* LUN address */
|
||||
if (lun)
|
||||
memcpy(desc->u.itmf.lun, lun, LUN_ADDRESS); /* LUN address */
|
||||
desc->u.itmf._resvd1 = 0;
|
||||
hton24(desc->u.itmf.d_id, d_id); /* FC vNIC only: Target D_ID */
|
||||
desc->u.itmf.r_a_tov = r_a_tov; /* FC vNIC only: R_A_TOV in msec */
|
||||
@@ -222,6 +223,35 @@ static inline void fnic_queue_rq_desc(struct vnic_rq *rq,
|
||||
vnic_rq_post(rq, os_buf, 0, dma_addr, len);
|
||||
}
|
||||
|
||||
static inline void fnic_queue_wq_copy_desc_nvme_io(struct vnic_wq_copy *wq,
|
||||
u32 req_id,
|
||||
u8 spl_flags,
|
||||
u32 sgl_cnt,
|
||||
u64 sgl_addr,
|
||||
u8 flags, u8 *nvme_cmd_iu,
|
||||
u16 cmd_len,
|
||||
u32 data_len,
|
||||
u32 d_id, u32 mss,
|
||||
u32 ratov, u32 edtov)
|
||||
{
|
||||
struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq);
|
||||
|
||||
desc->hdr.type = FCPIO_NVME_CMD; /* enum fcpio_type */
|
||||
desc->hdr.status = 0; /* header status entry */
|
||||
desc->hdr._resvd = 0; /* reserved */
|
||||
desc->hdr.tag.u.req_id = req_id; /* id for this request */
|
||||
desc->u.nvcmnd.sgl_cnt = sgl_cnt; /* scatter-gather list count */
|
||||
desc->u.nvcmnd.sgl_addr = sgl_addr; /* scatter-gather list addr */
|
||||
desc->u.nvcmnd._resvd1 = 0; /* reserved: should be 0 */
|
||||
desc->u.nvcmnd.flags = flags; /* command flags */
|
||||
memset(desc->u.nvcmnd.nvme_cmnd, 0, NVME_CMD_SZ);
|
||||
memcpy(desc->u.nvcmnd.nvme_cmnd, nvme_cmd_iu, cmd_len); /* SCSI CDB */
|
||||
desc->u.nvcmnd.cmd_len = cmd_len;
|
||||
desc->u.nvcmnd.data_len = data_len; /* length of data expected */
|
||||
hton24(desc->u.nvcmnd.d_id, d_id); /* FC vNIC only: Target D_ID */
|
||||
|
||||
vnic_wq_copy_post(wq);
|
||||
}
|
||||
|
||||
struct fnic;
|
||||
|
||||
|
||||
+137
-114
@@ -96,7 +96,7 @@ static const char *fnic_ioreq_state_to_str(unsigned int state)
|
||||
return fnic_ioreq_state_str[state];
|
||||
}
|
||||
|
||||
static const char *fnic_fcpio_status_to_str(unsigned int status)
|
||||
const char *fnic_fcpio_status_to_str(unsigned int status)
|
||||
{
|
||||
if (status >= ARRAY_SIZE(fcpio_status_str) || !fcpio_status_str[status])
|
||||
return "unknown";
|
||||
@@ -145,10 +145,11 @@ unsigned int fnic_count_ioreqs(struct fnic *fnic, u32 portid)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
|
||||
fnic_scsi_io_iter(fnic, fnic_count_portid_ioreqs_iter,
|
||||
&portid, &count);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
fnic_scsi_io_iter(fnic, fnic_count_portid_ioreqs_iter,
|
||||
&portid, &count);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"portid = 0x%x count = %u\n", portid, count);
|
||||
return count;
|
||||
}
|
||||
@@ -180,13 +181,13 @@ fnic_count_lun_ioreqs(struct fnic *fnic, struct scsi_device *scsi_device)
|
||||
fnic_scsi_io_iter(fnic, fnic_count_lun_ioreqs_iter,
|
||||
scsi_device, &count);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"lun = %p count = %u\n", scsi_device, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Free up Copy Wq descriptors. Called with copy_wq lock held */
|
||||
static int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq, unsigned int hwq)
|
||||
int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq, unsigned int hwq)
|
||||
{
|
||||
/* if no Ack received from firmware, then nothing to clean */
|
||||
if (!fnic->fw_ack_recd[hwq])
|
||||
@@ -268,7 +269,7 @@ int fnic_fw_reset_handler(struct fnic *fnic)
|
||||
if (!vnic_wq_copy_desc_avail(wq))
|
||||
ret = -EAGAIN;
|
||||
else {
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"ioreq_count: %u\n", ioreq_count);
|
||||
fnic_queue_wq_copy_desc_fw_reset(wq, SCSI_NO_TAG);
|
||||
atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs);
|
||||
@@ -283,11 +284,11 @@ int fnic_fw_reset_handler(struct fnic *fnic)
|
||||
|
||||
if (!ret) {
|
||||
atomic64_inc(&fnic->fnic_stats.reset_stats.fw_resets);
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"Issued fw reset\n");
|
||||
} else {
|
||||
fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"Failed to issue fw reset\n");
|
||||
}
|
||||
|
||||
@@ -326,13 +327,13 @@ int fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id)
|
||||
fc_id, gw_mac,
|
||||
fnic->iport.fpma,
|
||||
iport->r_a_tov, iport->e_d_tov);
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"FLOGI FIP reg issued fcid: 0x%x src %p dest %p\n",
|
||||
fc_id, fnic->iport.fpma, gw_mac);
|
||||
} else {
|
||||
fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG,
|
||||
format, fc_id, gw_mac);
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"FLOGI reg issued fcid 0x%x dest %p\n",
|
||||
fc_id, gw_mac);
|
||||
}
|
||||
@@ -413,7 +414,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
|
||||
free_wq_copy_descs(fnic, wq, hwq);
|
||||
|
||||
if (unlikely(!vnic_wq_copy_desc_avail(wq))) {
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"fnic_queue_wq_copy_desc failure - no descriptors\n");
|
||||
atomic64_inc(&misc_stats->io_cpwq_alloc_failures);
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
@@ -478,7 +479,7 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
|
||||
|
||||
rport = starget_to_rport(scsi_target(sc->device));
|
||||
if (!rport) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"returning DID_NO_CONNECT for IO as rport is NULL\n");
|
||||
sc->result = DID_NO_CONNECT << 16;
|
||||
done(sc);
|
||||
@@ -487,7 +488,7 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
|
||||
|
||||
ret = fc_remote_port_chkready(rport);
|
||||
if (ret) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"rport is not ready\n");
|
||||
atomic64_inc(&fnic_stats->misc_stats.tport_not_ready);
|
||||
sc->result = ret;
|
||||
@@ -501,7 +502,7 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
|
||||
|
||||
if (iport->state != FNIC_IPORT_STATE_READY) {
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"returning DID_NO_CONNECT for IO as iport state: %d\n",
|
||||
iport->state);
|
||||
sc->result = DID_NO_CONNECT << 16;
|
||||
@@ -515,13 +516,13 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
|
||||
rdd_data = rport->dd_data;
|
||||
tport = rdd_data->tport;
|
||||
if (!tport || (rdd_data->iport != iport)) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"dd_data not yet set in SCSI for rport portid: 0x%x\n",
|
||||
rport->port_id);
|
||||
tport = fnic_find_tport_by_fcid(iport, rport->port_id);
|
||||
if (!tport) {
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"returning DID_BUS_BUSY for IO as tport not found for: 0x%x\n",
|
||||
rport->port_id);
|
||||
sc->result = DID_BUS_BUSY << 16;
|
||||
@@ -544,7 +545,7 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
|
||||
if ((tport->state != FDLS_TGT_STATE_READY)
|
||||
&& (tport->state != FDLS_TGT_STATE_ADISC)) {
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"returning DID_NO_CONNECT for IO as tport state: %d\n",
|
||||
tport->state);
|
||||
sc->result = DID_NO_CONNECT << 16;
|
||||
@@ -564,7 +565,7 @@ enum scsi_qc_status fnic_queuecommand(struct Scsi_Host *shost,
|
||||
|
||||
if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET))) {
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"fnic flags FW reset: 0x%lx. Returning SCSI_MLQUEUE_HOST_BUSY\n",
|
||||
fnic->state_flags);
|
||||
return SCSI_MLQUEUE_HOST_BUSY;
|
||||
@@ -704,7 +705,7 @@ out:
|
||||
atomic_dec(&tport->in_flight);
|
||||
|
||||
if (lun0_delay) {
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"LUN0 delay\n");
|
||||
mdelay(LUN0_DELAY_TIME);
|
||||
}
|
||||
@@ -732,7 +733,10 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic,
|
||||
atomic64_inc(&reset_stats->fw_reset_completions);
|
||||
|
||||
/* Clean up all outstanding io requests */
|
||||
fnic_cleanup_io(fnic, SCSI_NO_TAG);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
fnic_cleanup_io(fnic, SCSI_NO_TAG);
|
||||
else if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_cleanup_all_nvme_ios(fnic);
|
||||
|
||||
atomic64_set(&fnic->fnic_stats.fw_stats.active_fw_reqs, 0);
|
||||
atomic64_set(&fnic->fnic_stats.io_stats.active_ios, 0);
|
||||
@@ -744,12 +748,12 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic,
|
||||
if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) {
|
||||
/* Check status of reset completion */
|
||||
if (!hdr_status) {
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"reset cmpl success\n");
|
||||
/* Ready to send flogi out */
|
||||
fnic->state = FNIC_IN_ETH_MODE;
|
||||
} else {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"reset failed with header status: %s\n",
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
|
||||
@@ -758,7 +762,7 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic,
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"Unexpected state while processing reset completion: %s\n",
|
||||
fnic_state_to_str(fnic->state));
|
||||
atomic64_inc(&reset_stats->fw_reset_failures);
|
||||
@@ -810,19 +814,18 @@ static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic,
|
||||
|
||||
/* Check flogi registration completion status */
|
||||
if (!hdr_status) {
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"FLOGI reg succeeded\n");
|
||||
fnic->state = FNIC_IN_FC_MODE;
|
||||
} else {
|
||||
FNIC_SCSI_DBG(KERN_DEBUG,
|
||||
fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"fnic flogi reg failed: %s\n",
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
fnic->state = FNIC_IN_ETH_MODE;
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Unexpected fnic state %s while"
|
||||
" processing flogi reg completion\n",
|
||||
fnic_state_to_str(fnic->state));
|
||||
@@ -895,7 +898,7 @@ static inline void fnic_fcpio_ack_handler(struct fnic *fnic,
|
||||
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[wq_index], flags);
|
||||
FNIC_TRACE(fnic_fcpio_ack_handler,
|
||||
fnic->host->host_no, 0, 0, ox_id_tag[2], ox_id_tag[3],
|
||||
fnic->fnic_num, 0, 0, ox_id_tag[2], ox_id_tag[3],
|
||||
ox_id_tag[4], ox_id_tag[5]);
|
||||
}
|
||||
|
||||
@@ -933,19 +936,19 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind
|
||||
hwq = blk_mq_unique_tag_to_hwq(mqtag);
|
||||
|
||||
if (hwq != cq_index) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ",
|
||||
hwq, mqtag, tag, cq_index);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hdr status: %s icmnd completion on the wrong queue\n",
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
}
|
||||
|
||||
if (tag >= fnic->fnic_max_tag_id) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ",
|
||||
hwq, mqtag, tag, cq_index);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hdr status: %s Out of range tag\n",
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
return;
|
||||
@@ -957,7 +960,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind
|
||||
if (!sc) {
|
||||
atomic64_inc(&fnic_stats->io_stats.sc_null);
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"icmnd_cmpl sc is null - "
|
||||
"hdr status = %s tag = 0x%x desc = 0x%p\n",
|
||||
fnic_fcpio_status_to_str(hdr_status), id, desc);
|
||||
@@ -985,7 +988,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind
|
||||
atomic64_inc(&fnic_stats->io_stats.ioreq_null);
|
||||
fnic_priv(sc)->flags |= FNIC_IO_REQ_NULL;
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"icmnd_cmpl io_req is null - "
|
||||
"hdr status = %s tag = 0x%x sc 0x%p\n",
|
||||
fnic_fcpio_status_to_str(hdr_status), id, sc);
|
||||
@@ -1012,7 +1015,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind
|
||||
if(FCPIO_ABORTED == hdr_status)
|
||||
fnic_priv(sc)->flags |= FNIC_IO_ABORTED;
|
||||
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"icmnd_cmpl abts pending "
|
||||
"hdr status = %s tag = 0x%x sc = 0x%p "
|
||||
"scsi_status = %x residual = %d\n",
|
||||
@@ -1044,7 +1047,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind
|
||||
if (icmnd_cmpl->scsi_status == SAM_STAT_TASK_SET_FULL)
|
||||
atomic64_inc(&fnic_stats->misc_stats.queue_fulls);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"xfer_len: %llu", xfer_len);
|
||||
break;
|
||||
|
||||
@@ -1107,7 +1110,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_ind
|
||||
|
||||
if (hdr_status != FCPIO_SUCCESS) {
|
||||
atomic64_inc(&fnic_stats->io_stats.io_failures);
|
||||
shost_printk(KERN_ERR, fnic->host, "hdr status = %s\n",
|
||||
fnic_printk(KERN_ERR, fnic, "hdr status = %s\n",
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
}
|
||||
|
||||
@@ -1200,27 +1203,27 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
hwq = blk_mq_unique_tag_to_hwq(id & FNIC_TAG_MASK);
|
||||
|
||||
if (hwq != cq_index) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ",
|
||||
hwq, mqtag, tag, cq_index);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hdr status: %s ITMF completion on the wrong queue\n",
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
}
|
||||
|
||||
if (tag > fnic->fnic_max_tag_id) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ",
|
||||
hwq, mqtag, tag, cq_index);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hdr status: %s Tag out of range\n",
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
return;
|
||||
} else if ((tag == fnic->fnic_max_tag_id) && !(id & FNIC_TAG_DEV_RST)) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ",
|
||||
hwq, mqtag, tag, cq_index);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hdr status: %s Tag out of range\n",
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
return;
|
||||
@@ -1243,7 +1246,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
if (!sc) {
|
||||
atomic64_inc(&fnic_stats->io_stats.sc_null);
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"itmf_cmpl sc is null - hdr status = %s tag = 0x%x\n",
|
||||
fnic_fcpio_status_to_str(hdr_status), tag);
|
||||
return;
|
||||
@@ -1255,7 +1258,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
atomic64_inc(&fnic_stats->io_stats.ioreq_null);
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_REQ_NULL;
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"itmf_cmpl io_req is null - "
|
||||
"hdr status = %s tag = 0x%x sc 0x%p\n",
|
||||
fnic_fcpio_status_to_str(hdr_status), tag, sc);
|
||||
@@ -1266,7 +1269,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
if ((id & FNIC_TAG_ABORT) && (id & FNIC_TAG_DEV_RST)) {
|
||||
/* Abort and terminate completion of device reset req */
|
||||
/* REVISIT : Add asserts about various flags */
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Abt/term completion received\n",
|
||||
hwq, mqtag, tag,
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
@@ -1278,7 +1281,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
} else if (id & FNIC_TAG_ABORT) {
|
||||
/* Completion of abort cmd */
|
||||
shost_printk(KERN_DEBUG, fnic->host,
|
||||
fnic_printk(KERN_DEBUG, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x Abort header status: %s\n",
|
||||
hwq, mqtag, tag,
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
@@ -1293,7 +1296,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
&term_stats->terminate_fw_timeouts);
|
||||
break;
|
||||
case FCPIO_ITMF_REJECTED:
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"abort reject recd. id %d\n",
|
||||
(int)(id & FNIC_TAG_MASK));
|
||||
break;
|
||||
@@ -1328,7 +1331,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE)))
|
||||
atomic64_inc(&misc_stats->no_icmnd_itmf_cmpls);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"abts cmpl recd. id %d status %s\n",
|
||||
(int)(id & FNIC_TAG_MASK),
|
||||
fnic_fcpio_status_to_str(hdr_status));
|
||||
@@ -1341,11 +1344,11 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
if (io_req->abts_done) {
|
||||
complete(io_req->abts_done);
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
shost_printk(KERN_INFO, fnic->host,
|
||||
fnic_printk(KERN_INFO, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x Waking up abort thread\n",
|
||||
hwq, mqtag, tag);
|
||||
} else {
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Completing IO\n",
|
||||
hwq, mqtag,
|
||||
tag, fnic_fcpio_status_to_str(hdr_status));
|
||||
@@ -1376,7 +1379,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
}
|
||||
} else if (id & FNIC_TAG_DEV_RST) {
|
||||
/* Completion of device reset */
|
||||
shost_printk(KERN_INFO, fnic->host,
|
||||
fnic_printk(KERN_INFO, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x DR hst: %s\n",
|
||||
hwq, mqtag,
|
||||
tag, fnic_fcpio_status_to_str(hdr_status));
|
||||
@@ -1388,7 +1391,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
sc->device->host->host_no, id, sc,
|
||||
jiffies_to_msecs(jiffies - start_time),
|
||||
desc, 0, fnic_flags_and_state(sc));
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Terminate pending\n",
|
||||
hwq, mqtag,
|
||||
tag, fnic_fcpio_status_to_str(hdr_status));
|
||||
@@ -1401,7 +1404,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
sc->device->host->host_no, id, sc,
|
||||
jiffies_to_msecs(jiffies - start_time),
|
||||
desc, 0, fnic_flags_and_state(sc));
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"dev reset cmpl recd after time out. "
|
||||
"id %d status %s\n",
|
||||
(int)(id & FNIC_TAG_MASK),
|
||||
@@ -1410,7 +1413,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
}
|
||||
fnic_priv(sc)->state = FNIC_IOREQ_CMD_COMPLETE;
|
||||
fnic_priv(sc)->flags |= FNIC_DEV_RST_DONE;
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x hst: %s DR completion received\n",
|
||||
hwq, mqtag,
|
||||
tag, fnic_fcpio_status_to_str(hdr_status));
|
||||
@@ -1419,7 +1422,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_inde
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
|
||||
} else {
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"%s: Unexpected itmf io state: hwq: %d tag 0x%x %s\n",
|
||||
__func__, hwq, id, fnic_ioreq_state_to_str(fnic_priv(sc)->state));
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
@@ -1443,6 +1446,7 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev,
|
||||
case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */
|
||||
case FCPIO_FLOGI_FIP_REG_CMPL: /* fw completed flogi_fip_reg */
|
||||
case FCPIO_RESET_CMPL: /* fw completed reset */
|
||||
case FCPIO_NVME_ERSP_HW_CMPL: /* fw completed NVMe ERSP */
|
||||
atomic64_dec(&fnic->fnic_stats.fw_stats.active_fw_reqs);
|
||||
break;
|
||||
default:
|
||||
@@ -1457,11 +1461,22 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev,
|
||||
break;
|
||||
|
||||
case FCPIO_ICMND_CMPL: /* fw completed a command */
|
||||
fnic_fcpio_icmnd_cmpl_handler(fnic, cq_index, desc);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
fnic_fcpio_icmnd_cmpl_handler(fnic, cq_index, desc);
|
||||
else if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_fcpio_nvme_fast_cmpl_handler(fnic, desc);
|
||||
break;
|
||||
|
||||
case FCPIO_NVME_ERSP_HW_CMPL: /* fw completed NVMe ERSP */
|
||||
if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_fcpio_ersp_cmpl_handler(fnic, desc, 1);
|
||||
break;
|
||||
|
||||
case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/
|
||||
fnic_fcpio_itmf_cmpl_handler(fnic, cq_index, desc);
|
||||
if (IS_FNIC_FCP_INITIATOR(fnic))
|
||||
fnic_fcpio_itmf_cmpl_handler(fnic, cq_index, desc);
|
||||
else if (IS_FNIC_NVME_INITIATOR(fnic))
|
||||
nvfnic_fcpio_nvme_itmf_cmpl_handler(fnic, desc);
|
||||
break;
|
||||
|
||||
case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */
|
||||
@@ -1474,7 +1489,7 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev,
|
||||
break;
|
||||
|
||||
default:
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"firmware completion type %d\n",
|
||||
desc->hdr.type);
|
||||
break;
|
||||
@@ -1535,7 +1550,7 @@ static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data)
|
||||
io_req = fnic_priv(sc)->io_req;
|
||||
if (!io_req) {
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d mqtag: 0x%x tag: 0x%x flags: 0x%x No ioreq. Returning\n",
|
||||
hwq, mqtag, tag, fnic_priv(sc)->flags);
|
||||
return true;
|
||||
@@ -1573,7 +1588,7 @@ static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data)
|
||||
mempool_free(io_req, fnic->io_req_pool);
|
||||
|
||||
sc->result = DID_TRANSPORT_DISRUPTED << 16;
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"mqtag: 0x%x tag: 0x%x sc: 0x%p duration = %lu DID_TRANSPORT_DISRUPTED\n",
|
||||
mqtag, tag, sc, (jiffies - start_time));
|
||||
|
||||
@@ -1605,7 +1620,7 @@ static void fnic_cleanup_io(struct fnic *fnic, int exclude_id)
|
||||
struct scsi_cmnd *sc = NULL;
|
||||
|
||||
io_count = fnic_count_all_ioreqs(fnic);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Outstanding ioreq count: %d active io count: %lld Waiting\n",
|
||||
io_count,
|
||||
atomic64_read(&fnic->fnic_stats.io_stats.active_ios));
|
||||
@@ -1630,7 +1645,7 @@ static void fnic_cleanup_io(struct fnic *fnic, int exclude_id)
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags);
|
||||
|
||||
while ((io_count = fnic_count_all_ioreqs(fnic))) {
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Outstanding ioreq count: %d active io count: %lld Waiting\n",
|
||||
io_count,
|
||||
atomic64_read(&fnic->fnic_stats.io_stats.active_ios));
|
||||
@@ -1650,6 +1665,15 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq,
|
||||
unsigned long start_time = 0;
|
||||
uint16_t hwq;
|
||||
|
||||
/*
|
||||
* Clean up outstanding NVMe requests if firmware reset did not
|
||||
* complete them before WQ copy cleanup.
|
||||
*/
|
||||
if (IS_FNIC_NVME_INITIATOR(fnic)) {
|
||||
nvfnic_cleanup_all_nvme_ios(fnic);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get the tag reference */
|
||||
fcpio_tag_id_dec(&desc->hdr.tag, &id);
|
||||
id &= FNIC_TAG_MASK;
|
||||
@@ -1686,7 +1710,7 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq,
|
||||
|
||||
wq_copy_cleanup_scsi_cmd:
|
||||
sc->result = DID_NO_CONNECT << 16;
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, "wq_copy_cleanup_handler:"
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic, "wq_copy_cleanup_handler:"
|
||||
" DID_NO_CONNECT\n");
|
||||
|
||||
FNIC_TRACE(fnic_wq_copy_cleanup_handler,
|
||||
@@ -1730,7 +1754,7 @@ static inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag,
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
atomic_dec(&fnic->in_flight);
|
||||
atomic_dec(&tport->in_flight);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"fnic_queue_abort_io_req: failure: no descriptors\n");
|
||||
atomic64_inc(&misc_stats->abts_cpwq_alloc_failures);
|
||||
return 1;
|
||||
@@ -1775,7 +1799,7 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data)
|
||||
hwq = blk_mq_unique_tag_to_hwq(abt_tag);
|
||||
|
||||
if (!sc) {
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"sc is NULL abt_tag: 0x%x hwq: %d\n", abt_tag, hwq);
|
||||
return true;
|
||||
}
|
||||
@@ -1789,7 +1813,7 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data)
|
||||
|
||||
if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) &&
|
||||
!(fnic_priv(sc)->flags & FNIC_DEV_RST_ISSUED)) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d abt_tag: 0x%x flags: 0x%x Device reset is not pending\n",
|
||||
hwq, abt_tag, fnic_priv(sc)->flags);
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
@@ -1806,16 +1830,16 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data)
|
||||
}
|
||||
|
||||
if (io_req->abts_done) {
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"fnic_rport_exch_reset: io_req->abts_done is set state is %s\n",
|
||||
fnic_ioreq_state_to_str(fnic_priv(sc)->state));
|
||||
}
|
||||
|
||||
if (!(fnic_priv(sc)->flags & FNIC_IO_ISSUED)) {
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"rport_exch_reset IO not yet issued %p abt_tag 0x%x",
|
||||
sc, abt_tag);
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"flags %x state %d\n", fnic_priv(sc)->flags,
|
||||
fnic_priv(sc)->state);
|
||||
}
|
||||
@@ -1826,13 +1850,13 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data)
|
||||
if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) {
|
||||
atomic64_inc(&reset_stats->device_reset_terminates);
|
||||
abt_tag |= FNIC_TAG_DEV_RST;
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"dev reset sc 0x%p\n", sc);
|
||||
}
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"fnic_rport_exch_reset: dev rst sc 0x%p\n", sc);
|
||||
WARN_ON_ONCE(io_req->abts_done);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"fnic_rport_reset_exch: Issuing abts\n");
|
||||
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
@@ -1850,7 +1874,7 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data)
|
||||
* lun reset
|
||||
*/
|
||||
spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d abt_tag: 0x%x flags: 0x%x Queuing abort failed\n",
|
||||
hwq, abt_tag, fnic_priv(sc)->flags);
|
||||
if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING)
|
||||
@@ -1881,7 +1905,7 @@ void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id)
|
||||
.term_cnt = 0,
|
||||
};
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"fnic rport exchange reset for tport: 0x%06x\n",
|
||||
port_id);
|
||||
|
||||
@@ -1889,7 +1913,7 @@ void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id)
|
||||
return;
|
||||
|
||||
io_count = fnic_count_ioreqs(fnic, port_id);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Starting terminates: rport:0x%x portid-io-count: %d active-io-count: %lld\n",
|
||||
port_id, io_count,
|
||||
atomic64_read(&fnic->fnic_stats.io_stats.active_ios));
|
||||
@@ -1915,7 +1939,7 @@ void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id)
|
||||
while ((io_count = fnic_count_ioreqs(fnic, port_id)))
|
||||
schedule_timeout(msecs_to_jiffies(1000));
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"rport: 0x%x remaining portid-io-count: %d ",
|
||||
port_id, io_count);
|
||||
}
|
||||
@@ -2040,10 +2064,10 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
|
||||
tport = rdd_data->tport;
|
||||
|
||||
if (!tport) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"Abort cmd called after tport delete! rport fcid: 0x%x",
|
||||
rport->port_id);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"lun: %llu hwq: 0x%x mqtag: 0x%x Op: 0x%x flags: 0x%x\n",
|
||||
sc->device->lun, hwq, mqtag,
|
||||
sc->cmnd[0], fnic_priv(sc)->flags);
|
||||
@@ -2052,18 +2076,18 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
|
||||
goto fnic_abort_cmd_end;
|
||||
}
|
||||
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"Abort cmd called rport fcid: 0x%x lun: %llu hwq: 0x%x mqtag: 0x%x",
|
||||
rport->port_id, sc->device->lun, hwq, mqtag);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"Op: 0x%x flags: 0x%x\n",
|
||||
sc->cmnd[0],
|
||||
fnic_priv(sc)->flags);
|
||||
|
||||
if (iport->state != FNIC_IPORT_STATE_READY) {
|
||||
atomic64_inc(&fnic_stats->misc_stats.iport_not_ready);
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"iport NOT in READY state");
|
||||
ret = FAILED;
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
@@ -2072,7 +2096,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
|
||||
|
||||
if ((tport->state != FDLS_TGT_STATE_READY) &&
|
||||
(tport->state != FDLS_TGT_STATE_ADISC)) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"tport state: %d\n", tport->state);
|
||||
ret = FAILED;
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
@@ -2123,7 +2147,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
|
||||
else
|
||||
atomic64_inc(&abts_stats->abort_issued_greater_than_60_sec);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"CDB Opcode: 0x%02x Abort issued time: %lu msec\n",
|
||||
sc->cmnd[0], abt_issued_time);
|
||||
/*
|
||||
@@ -2214,7 +2238,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc)
|
||||
|
||||
if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE))) {
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"Issuing host reset due to out of order IO\n");
|
||||
|
||||
ret = FAILED;
|
||||
@@ -2262,7 +2286,7 @@ fnic_abort_cmd_end:
|
||||
(u64)sc->cmnd[4] << 8 | sc->cmnd[5]),
|
||||
fnic_flags_and_state(sc));
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Returning from abort cmd type %x %s\n", task_req,
|
||||
(ret == SUCCESS) ?
|
||||
"SUCCESS" : "FAILED");
|
||||
@@ -2303,7 +2327,7 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic,
|
||||
free_wq_copy_descs(fnic, wq, hwq);
|
||||
|
||||
if (!vnic_wq_copy_desc_avail(wq)) {
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"queue_dr_io_req failure - no descriptors\n");
|
||||
atomic64_inc(&misc_stats->devrst_cpwq_alloc_failures);
|
||||
ret = -EAGAIN;
|
||||
@@ -2371,7 +2395,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data)
|
||||
* Found IO that is still pending with firmware and
|
||||
* belongs to the LUN that we are resetting
|
||||
*/
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Found IO in %s on lun\n",
|
||||
fnic_ioreq_state_to_str(fnic_priv(sc)->state));
|
||||
|
||||
@@ -2381,14 +2405,14 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data)
|
||||
}
|
||||
if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) &&
|
||||
(!(fnic_priv(sc)->flags & FNIC_DEV_RST_ISSUED))) {
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"dev rst not pending sc 0x%p\n", sc);
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (io_req->abts_done)
|
||||
shost_printk(KERN_ERR, fnic->host,
|
||||
fnic_printk(KERN_ERR, fnic,
|
||||
"%s: io_req->abts_done is set state is %s\n",
|
||||
__func__, fnic_ioreq_state_to_str(fnic_priv(sc)->state));
|
||||
old_ioreq_state = fnic_priv(sc)->state;
|
||||
@@ -2404,7 +2428,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data)
|
||||
BUG_ON(io_req->abts_done);
|
||||
|
||||
if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) {
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"dev rst sc 0x%p\n", sc);
|
||||
}
|
||||
|
||||
@@ -2426,7 +2450,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data)
|
||||
fnic_priv(sc)->state = old_ioreq_state;
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
iter_data->ret = FAILED;
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"hwq: %d abt_tag: 0x%lx Abort could not be queued\n",
|
||||
hwq, abt_tag);
|
||||
return false;
|
||||
@@ -2518,7 +2542,7 @@ static int fnic_clean_pending_aborts(struct fnic *fnic,
|
||||
ret = 1;
|
||||
|
||||
clean_pending_aborts_end:
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"exit status: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -2568,7 +2592,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
rport = starget_to_rport(scsi_target(sc->device));
|
||||
|
||||
spin_lock_irqsave(&fnic->fnic_lock, flags);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"fcid: 0x%x lun: %llu hwq: %d mqtag: 0x%x flags: 0x%x Device reset\n",
|
||||
rport->port_id, sc->device->lun, hwq, mqtag,
|
||||
fnic_priv(sc)->flags);
|
||||
@@ -2576,7 +2600,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
rdd_data = rport->dd_data;
|
||||
tport = rdd_data->tport;
|
||||
if (!tport) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"Dev rst called after tport delete! rport fcid: 0x%x lun: %llu\n",
|
||||
rport->port_id, sc->device->lun);
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
@@ -2585,7 +2609,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
|
||||
if (iport->state != FNIC_IPORT_STATE_READY) {
|
||||
atomic64_inc(&fnic_stats->misc_stats.iport_not_ready);
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"iport NOT in READY state");
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
goto fnic_device_reset_end;
|
||||
@@ -2593,7 +2617,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
|
||||
if ((tport->state != FDLS_TGT_STATE_READY) &&
|
||||
(tport->state != FDLS_TGT_STATE_ADISC)) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"tport state: %d\n", tport->state);
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
goto fnic_device_reset_end;
|
||||
@@ -2656,7 +2680,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
fnic_priv(sc)->lr_status = FCPIO_INVALID_CODE;
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num, "TAG %x\n", mqtag);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic, "TAG %x\n", mqtag);
|
||||
|
||||
/*
|
||||
* issue the device reset, if enqueue failed, clean up the ioreq
|
||||
@@ -2707,13 +2731,13 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
io_req = fnic_priv(sc)->io_req;
|
||||
if (!io_req) {
|
||||
spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"io_req is null mqtag 0x%x sc 0x%p\n", mqtag, sc);
|
||||
goto fnic_device_reset_end;
|
||||
}
|
||||
|
||||
if (exit_dr) {
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"Host reset called for fnic. Exit device reset\n");
|
||||
io_req->dr_done = NULL;
|
||||
goto fnic_device_reset_clean;
|
||||
@@ -2728,7 +2752,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
*/
|
||||
if (status == FCPIO_INVALID_CODE) {
|
||||
atomic64_inc(&reset_stats->device_reset_timeouts);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Device reset timed out\n");
|
||||
fnic_priv(sc)->flags |= FNIC_DEV_RST_TIMED_OUT;
|
||||
int_to_scsilun(sc->device->lun, &fc_lun);
|
||||
@@ -2740,8 +2764,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
/* Completed, but not successful, clean up the io_req, return fail */
|
||||
if (status != FCPIO_SUCCESS) {
|
||||
spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags);
|
||||
FNIC_SCSI_DBG(KERN_DEBUG,
|
||||
fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Device reset completed - failed\n");
|
||||
io_req = fnic_priv(sc)->io_req;
|
||||
goto fnic_device_reset_clean;
|
||||
@@ -2757,7 +2780,7 @@ int fnic_device_reset(struct scsi_cmnd *sc)
|
||||
if (fnic_clean_pending_aborts(fnic, sc, new_sc)) {
|
||||
spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags);
|
||||
io_req = fnic_priv(sc)->io_req;
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Device reset failed: Cannot abort all IOs\n");
|
||||
goto fnic_device_reset_clean;
|
||||
}
|
||||
@@ -2811,13 +2834,13 @@ fnic_device_reset_end:
|
||||
ret = FAILED;
|
||||
break;
|
||||
}
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"Cannot clean up all IOs for the LUN\n");
|
||||
schedule_timeout(msecs_to_jiffies(1000));
|
||||
count++;
|
||||
}
|
||||
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_DEBUG, fnic,
|
||||
"Returning from device reset %s\n",
|
||||
(ret == SUCCESS) ?
|
||||
"SUCCESS" : "FAILED");
|
||||
@@ -2852,13 +2875,13 @@ void fnic_reset(struct Scsi_Host *shost)
|
||||
fnic = *((struct fnic **) shost_priv(shost));
|
||||
reset_stats = &fnic->fnic_stats.reset_stats;
|
||||
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"Issuing fnic reset\n");
|
||||
|
||||
atomic64_inc(&reset_stats->fnic_resets);
|
||||
fnic_post_flogo_linkflap(fnic);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"Returning from fnic reset");
|
||||
|
||||
atomic64_inc(&reset_stats->fnic_reset_completions);
|
||||
@@ -2869,7 +2892,7 @@ int fnic_issue_fc_host_lip(struct Scsi_Host *shost)
|
||||
int ret = 0;
|
||||
struct fnic *fnic = *((struct fnic **) shost_priv(shost));
|
||||
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"FC host lip issued");
|
||||
|
||||
ret = fnic_host_reset(shost);
|
||||
@@ -2895,7 +2918,7 @@ int fnic_host_reset(struct Scsi_Host *shost)
|
||||
spin_lock_irqsave(&fnic->fnic_lock, flags);
|
||||
if (fnic->reset_in_progress == IN_PROGRESS) {
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
FNIC_SCSI_DBG(KERN_WARNING, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_WARNING, fnic,
|
||||
"Firmware reset in progress. Skipping another host reset\n");
|
||||
return SUCCESS;
|
||||
}
|
||||
@@ -2933,7 +2956,7 @@ int fnic_host_reset(struct Scsi_Host *shost)
|
||||
}
|
||||
spin_unlock_irqrestore(&fnic->fnic_lock, flags);
|
||||
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"host reset return status: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
@@ -2973,7 +2996,7 @@ static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data)
|
||||
* Found IO that is still pending with firmware and
|
||||
* belongs to the LUN that we are resetting
|
||||
*/
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_INFO, fnic,
|
||||
"hwq: %d tag: 0x%x Found IO in state: %s on lun\n",
|
||||
hwq, tag,
|
||||
fnic_ioreq_state_to_str(fnic_priv(sc)->state));
|
||||
@@ -3027,7 +3050,7 @@ int fnic_eh_host_reset_handler(struct scsi_cmnd *sc)
|
||||
struct Scsi_Host *shost = sc->device->host;
|
||||
struct fnic *fnic = *((struct fnic **) shost_priv(shost));
|
||||
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic->host, fnic->fnic_num,
|
||||
FNIC_SCSI_DBG(KERN_ERR, fnic,
|
||||
"SCSI error handling: fnic host reset");
|
||||
|
||||
ret = fnic_host_reset(shost);
|
||||
|
||||
@@ -29,6 +29,15 @@ struct io_path_stats {
|
||||
atomic64_t io_greater_than_30000_msec;
|
||||
atomic64_t current_max_io_time;
|
||||
atomic64_t ios[FNIC_MQ_MAX_QUEUES];
|
||||
|
||||
atomic64_t nvme_io_reqs_rcvd;
|
||||
atomic64_t nvme_ios_queued_for_rsp;
|
||||
atomic64_t nvme_io_rsps_unqueued;
|
||||
atomic64_t nvme_io_rsps_sending;
|
||||
atomic64_t nvme_io_rsps_sent;
|
||||
atomic64_t nvme_num_ios_in_waitq;
|
||||
atomic64_t nvme_ios_in_waitq_3000_msec;
|
||||
atomic64_t nvme_ios_in_waitq_max_time;
|
||||
};
|
||||
|
||||
struct abort_stats {
|
||||
@@ -151,6 +160,17 @@ struct fnic_iport_stats {
|
||||
atomic64_t unsupported_frames_dropped;
|
||||
};
|
||||
|
||||
struct nvme_host_statistics {
|
||||
atomic64_t nvme_input_requests;
|
||||
atomic64_t nvme_output_requests;
|
||||
atomic64_t nvme_control_requests;
|
||||
atomic64_t nvme_ersps;
|
||||
atomic64_t nvme_ls_requests;
|
||||
atomic64_t nvme_ls_responses;
|
||||
atomic64_t nvme_ls_aborts;
|
||||
atomic64_t nvme_ls_abort_responses;
|
||||
};
|
||||
|
||||
struct fnic_stats {
|
||||
struct stats_timestamps stats_timestamps;
|
||||
struct io_path_stats io_stats;
|
||||
@@ -161,6 +181,7 @@ struct fnic_stats {
|
||||
struct vlan_stats vlan_stats;
|
||||
struct fc_host_statistics host_stats;
|
||||
struct misc_stats misc_stats;
|
||||
struct nvme_host_statistics nvme_stats;
|
||||
};
|
||||
|
||||
struct stats_debug_info {
|
||||
@@ -170,6 +191,13 @@ struct stats_debug_info {
|
||||
int buffer_len;
|
||||
};
|
||||
|
||||
struct fnic_nvmef_info {
|
||||
char *info_buffer;
|
||||
void *i_private;
|
||||
int buf_size;
|
||||
int buffer_len;
|
||||
};
|
||||
|
||||
int fnic_get_stats_data(struct stats_debug_info *, struct fnic_stats *);
|
||||
const char *fnic_role_to_str(unsigned int role);
|
||||
#endif /* _FNIC_STATS_H_ */
|
||||
|
||||
@@ -31,7 +31,8 @@ int fnic_fc_trace_cleared = 1;
|
||||
static DEFINE_SPINLOCK(fnic_fc_trace_lock);
|
||||
|
||||
static const char * const fnic_role_str[] = {
|
||||
[FNIC_ROLE_FCP_INITIATOR] = "FCP_Initiator",
|
||||
[FNIC_ROLE_FCP_INITIATOR] = "FCP_Initiator",
|
||||
[FNIC_ROLE_NVME_INITIATOR] = "NVMeF_Initiator",
|
||||
};
|
||||
|
||||
const char *fnic_role_to_str(unsigned int role)
|
||||
|
||||
@@ -381,7 +381,7 @@ static int vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
||||
if (result->color == color) {
|
||||
if (result->error) {
|
||||
err = -(int) result->error;
|
||||
if (err != ERR_ECMDUNKNOWN ||
|
||||
if (err != -ERR_ECMDUNKNOWN ||
|
||||
cmd != CMD_CAPABILITY)
|
||||
pr_err("%s:Error %d devcmd %d\n",
|
||||
pci_name(vdev->pdev),
|
||||
|
||||
@@ -430,7 +430,7 @@ struct vnic_devcmd_notify {
|
||||
struct vnic_devcmd_provinfo {
|
||||
u8 oui[3];
|
||||
u8 type;
|
||||
u8 data[];
|
||||
u8 data[0];
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -739,7 +739,7 @@ static struct isa_driver generic_NCR5380_isa_driver = {
|
||||
#ifdef CONFIG_PNP
|
||||
static const struct pnp_device_id generic_NCR5380_pnp_ids[] = {
|
||||
{ .id = "DTC436e", .driver_data = BOARD_DTC3181E },
|
||||
{ .id = "" }
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pnp, generic_NCR5380_pnp_ids);
|
||||
|
||||
|
||||
@@ -442,14 +442,15 @@ static void gvp11_remove(struct zorro_dev *z)
|
||||
*/
|
||||
|
||||
static struct zorro_device_id gvp11_zorro_tbl[] = {
|
||||
{ ZORRO_PROD_GVP_COMBO_030_R3_SCSI, ~0x00ffffff },
|
||||
{ ZORRO_PROD_GVP_SERIES_II, ~0x00ffffff },
|
||||
{ ZORRO_PROD_GVP_GFORCE_030_SCSI, ~0x01ffffff },
|
||||
{ ZORRO_PROD_GVP_A530_SCSI, ~0x01ffffff },
|
||||
{ ZORRO_PROD_GVP_COMBO_030_R4_SCSI, ~0x01ffffff },
|
||||
{ ZORRO_PROD_GVP_A1291, ~0x07ffffff },
|
||||
{ ZORRO_PROD_GVP_GFORCE_040_SCSI_1, ~0x07ffffff },
|
||||
{ 0 }
|
||||
/* .driver_data specifies the DMA mask */
|
||||
{ .id = ZORRO_PROD_GVP_COMBO_030_R3_SCSI, .driver_data = ~0x00ffffff },
|
||||
{ .id = ZORRO_PROD_GVP_SERIES_II, .driver_data = ~0x00ffffff },
|
||||
{ .id = ZORRO_PROD_GVP_GFORCE_030_SCSI, .driver_data = ~0x01ffffff },
|
||||
{ .id = ZORRO_PROD_GVP_A530_SCSI, .driver_data = ~0x01ffffff },
|
||||
{ .id = ZORRO_PROD_GVP_COMBO_030_R4_SCSI, .driver_data = ~0x01ffffff },
|
||||
{ .id = ZORRO_PROD_GVP_A1291, .driver_data = ~0x07ffffff },
|
||||
{ .id = ZORRO_PROD_GVP_GFORCE_040_SCSI_1, .driver_data = ~0x07ffffff },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(zorro, gvp11_zorro_tbl);
|
||||
|
||||
|
||||
@@ -252,10 +252,8 @@ int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
|
||||
|
||||
shost->dma_dev = dma_dev;
|
||||
|
||||
if (dma_dev->dma_mask) {
|
||||
shost->max_sectors = min_t(unsigned int, shost->max_sectors,
|
||||
dma_max_mapping_size(dma_dev) >> SECTOR_SHIFT);
|
||||
}
|
||||
shost->max_sectors = min_not_zero(shost->max_sectors,
|
||||
dma_max_mapping_size(dma_dev) >> SECTOR_SHIFT);
|
||||
|
||||
error = scsi_mq_setup_tags(shost);
|
||||
if (error)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
ibmvfc-objs := ibmvfc-core.o ibmvfc-nvme.o
|
||||
|
||||
obj-$(CONFIG_SCSI_IBMVSCSI) += ibmvscsi.o
|
||||
obj-$(CONFIG_SCSI_IBMVFC) += ibmvfc.o
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,573 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* ibmvfc-nvme.c -- IBM Power Virtual Fibre Channel NVMeoF HBA driver
|
||||
*
|
||||
* Written By: Tyrel Datwyler <tyreld@linux.ibm.com>, IBM Corporation
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2026
|
||||
*/
|
||||
|
||||
#include <linux/dmapool.h>
|
||||
#include <scsi/scsi_transport_fc.h>
|
||||
|
||||
#include "ibmvfc-nvme.h"
|
||||
|
||||
static unsigned int default_timeout = IBMVFC_DEFAULT_TIMEOUT;
|
||||
|
||||
static void ibmvfc_nvme_localport_delete(struct nvme_fc_local_port *lport)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
|
||||
vhost->nvme_local_port = NULL;
|
||||
complete(&vhost->nvme_delete_done);
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_remoteport_delete(struct nvme_fc_remote_port *rport)
|
||||
{
|
||||
struct ibmvfc_target *tgt = rport->private;
|
||||
|
||||
tgt->nvme_remote_port = NULL;
|
||||
complete(&tgt->nvme_delete_done);
|
||||
}
|
||||
|
||||
static int ibmvfc_nvme_create_queue(struct nvme_fc_local_port *lport, unsigned int qidx,
|
||||
u16 qsize, void **handle)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
struct ibmvfc_nvme_qhandle *qhandle;
|
||||
|
||||
if (!vhost->nvme_scrqs.active_queues)
|
||||
return -ENODEV;
|
||||
|
||||
qhandle = kzalloc_obj(struct ibmvfc_nvme_qhandle);
|
||||
if (!qhandle)
|
||||
return -ENOMEM;
|
||||
|
||||
qhandle->cpu_id = raw_smp_processor_id();
|
||||
qhandle->qidx = qidx;
|
||||
|
||||
/* Admin and first IO queue are both mapped to index 0 */
|
||||
if (qidx)
|
||||
qhandle->index = (qidx - 1) % vhost->nvme_scrqs.active_queues;
|
||||
else
|
||||
qhandle->index = qidx;
|
||||
|
||||
qhandle->queue = &vhost->nvme_scrqs.scrqs[qhandle->index];
|
||||
|
||||
*handle = qhandle;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_delete_queue(struct nvme_fc_local_port *lport, unsigned int qidx,
|
||||
void *handle)
|
||||
{
|
||||
kfree(handle);
|
||||
}
|
||||
|
||||
static void ibmvfc_ls_req_done(struct ibmvfc_event *evt)
|
||||
{
|
||||
struct ibmvfc_target *tgt = evt->tgt;
|
||||
struct ibmvfc_passthru_mad *mad = &evt->xfer_iu->passthru;
|
||||
struct fcnvme_ls_rqst_w0 *ls_rqst;
|
||||
struct fcnvme_ls_cr_assoc_acc *ls_resp;
|
||||
u32 status = be16_to_cpu(mad->common.status);
|
||||
int rc = 0;
|
||||
|
||||
ls_rqst = (struct fcnvme_ls_rqst_w0 *)evt->ls_req->rqstaddr;
|
||||
ls_resp = (struct fcnvme_ls_cr_assoc_acc *)evt->ls_req->rspaddr;
|
||||
|
||||
switch (status) {
|
||||
case IBMVFC_MAD_SUCCESS:
|
||||
tgt_dbg(tgt, "ls_req succeeded\n");
|
||||
if ((ls_rqst->ls_cmd == FCNVME_LS_CREATE_ASSOCIATION) &&
|
||||
(ls_resp->hdr.w0.ls_cmd == FCNVME_LS_ACC)) {
|
||||
tgt->assoc_id = be64_to_cpu(ls_resp->associd.association_id);
|
||||
tgt_dbg(tgt, "assoc_id 0x%llx\n", tgt->assoc_id);
|
||||
}
|
||||
break;
|
||||
case IBMVFC_MAD_DRIVER_FAILED:
|
||||
break;
|
||||
case IBMVFC_MAD_FAILED:
|
||||
default:
|
||||
tgt_info(tgt, "ls_req failed: %s (%x:%x) rc=0x%02X\n",
|
||||
ibmvfc_get_cmd_error(be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error)),
|
||||
be16_to_cpu(mad->iu.status), be16_to_cpu(mad->iu.error), status);
|
||||
break;
|
||||
}
|
||||
|
||||
if (status)
|
||||
rc = -EIO;
|
||||
|
||||
evt->ls_req->done(evt->ls_req, rc);
|
||||
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
ibmvfc_free_event(evt);
|
||||
}
|
||||
|
||||
static void ibmvfc_init_ls_req(struct ibmvfc_event *evt, struct nvmefc_ls_req *ls_req)
|
||||
{
|
||||
struct ibmvfc_passthru_mad *mad = &evt->iu.passthru;
|
||||
|
||||
memset(mad, 0, sizeof(*mad));
|
||||
mad->common.version = cpu_to_be32(2);
|
||||
mad->common.opcode = cpu_to_be32(IBMVFC_NVMF_PASSTHRU);
|
||||
mad->common.length = cpu_to_be16(sizeof(*mad) - sizeof(mad->fc_iu) - sizeof(mad->iu));
|
||||
mad->cmd_ioba.va = cpu_to_be64((u64)be64_to_cpu(evt->crq.ioba) +
|
||||
offsetof(struct ibmvfc_passthru_mad, iu));
|
||||
mad->cmd_ioba.len = cpu_to_be32(sizeof(mad->iu));
|
||||
mad->iu.cmd_len = cpu_to_be32(ls_req->rqstlen);
|
||||
mad->iu.rsp_len = cpu_to_be32(ls_req->rsplen);
|
||||
mad->iu.cmd.va = cpu_to_be64(ls_req->rqstdma);
|
||||
mad->iu.cmd.len = cpu_to_be32(ls_req->rqstlen);
|
||||
mad->iu.rsp.va = cpu_to_be64(ls_req->rspdma);
|
||||
mad->iu.rsp.len = cpu_to_be32(ls_req->rsplen);
|
||||
}
|
||||
|
||||
static int ibmvfc_nvme_ls_req(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_ls_req *ls_req)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
struct ibmvfc_target *tgt = rport->private;
|
||||
struct ibmvfc_passthru_mad *mad;
|
||||
struct ibmvfc_event *evt;
|
||||
|
||||
kref_get(&tgt->kref);
|
||||
evt = ibmvfc_get_event(&vhost->crq);
|
||||
if (!evt) {
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ibmvfc_init_event(evt, ibmvfc_ls_req_done, IBMVFC_MAD_FORMAT);
|
||||
evt->tgt = tgt;
|
||||
evt->ls_req = ls_req;
|
||||
ls_req->private = evt;
|
||||
|
||||
ibmvfc_init_ls_req(evt, ls_req);
|
||||
mad = &evt->iu.passthru;
|
||||
mad->iu.flags = cpu_to_be32(IBMVFC_FC4_LS_DSC_CTRL);
|
||||
mad->iu.scsi_id = cpu_to_be64(tgt->scsi_id);
|
||||
mad->iu.cancel_key = cpu_to_be32((u64)evt);
|
||||
mad->iu.target_wwpn = cpu_to_be64(tgt->wwpn);
|
||||
|
||||
ibmvfc_dbg(vhost, "nvme_ls_req\n");
|
||||
if (ibmvfc_send_event(evt, vhost, IBMVFC_FC4_LS_PLUS_CANCEL_TIMEOUT)) {
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ibmvfc_sync_nvme_completion(struct ibmvfc_event *evt)
|
||||
{
|
||||
/* copy the response back */
|
||||
if (evt->sync_iu)
|
||||
*evt->sync_iu = *evt->xfer_iu;
|
||||
|
||||
complete(&evt->comp);
|
||||
}
|
||||
|
||||
static void ibmvfc_init_ls_abort(struct ibmvfc_event *evt, struct nvmefc_ls_req *ls_abort)
|
||||
{
|
||||
struct ibmvfc_tmf *tmf;
|
||||
struct ibmvfc_event *abt_evt = ls_abort->private;
|
||||
struct ibmvfc_target *tgt = abt_evt->tgt;
|
||||
struct ibmvfc_host *vhost = evt->vhost;
|
||||
|
||||
tmf = &evt->iu.tmf;
|
||||
memset(tmf, 0, sizeof(*tmf));
|
||||
tmf->common.version = cpu_to_be32(2);
|
||||
tmf->target_wwpn = cpu_to_be64(tgt->wwpn);
|
||||
tmf->common.opcode = cpu_to_be32(IBMVFC_NVMF_TMF_MAD);
|
||||
tmf->common.length = cpu_to_be16(sizeof(*tmf));
|
||||
if (vhost->state != IBMVFC_ACTIVE)
|
||||
if (!ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPRESS_ABTS))
|
||||
tmf->flags = cpu_to_be32(IBMVFC_TMF_SUPPRESS_ABTS);
|
||||
tmf->cancel_key = cpu_to_be32((u64)abt_evt);
|
||||
tmf->my_cancel_key = cpu_to_be32((u64)evt);
|
||||
tmf->assoc_id = cpu_to_be64(tgt->assoc_id);
|
||||
|
||||
init_completion(&evt->comp);
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_ls_abort(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_ls_req *ls_abort)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
struct ibmvfc_target *tgt = rport->private;
|
||||
struct ibmvfc_event *evt;
|
||||
union ibmvfc_iu rsp;
|
||||
unsigned long flags;
|
||||
u16 status;
|
||||
|
||||
evt = ibmvfc_get_event(&vhost->crq);
|
||||
if (!vhost->logged_in || !evt)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||
kref_get(&tgt->kref);
|
||||
ibmvfc_init_event(evt, ibmvfc_sync_nvme_completion, IBMVFC_MAD_FORMAT);
|
||||
ibmvfc_init_ls_abort(evt, ls_abort);
|
||||
evt->sync_iu = &rsp;
|
||||
|
||||
if (ibmvfc_send_event(evt, vhost, default_timeout))
|
||||
goto out;
|
||||
|
||||
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
||||
|
||||
wait_for_completion(&evt->comp);
|
||||
status = be16_to_cpu(rsp.mad_common.status);
|
||||
spin_lock_irqsave(vhost->host->host_lock, flags);
|
||||
ibmvfc_free_event(evt);
|
||||
out:
|
||||
spin_unlock_irqrestore(vhost->host->host_lock, flags);
|
||||
ibmvfc_dbg(vhost, "ls_abort: cancel failed with rc=%x\n", status);
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_done(struct ibmvfc_event *evt)
|
||||
{
|
||||
struct ibmvfc_cmd *vfc_cmd = &evt->xfer_iu->cmd;
|
||||
struct nvmefc_fcp_req *fcp_req = evt->fcp_req;
|
||||
struct nvme_fc_ersp_iu *ersp = (struct nvme_fc_ersp_iu *)fcp_req->rspaddr;
|
||||
struct nvme_completion *cqe = &ersp->cqe;
|
||||
struct nvme_command *sqe = &((struct nvme_fc_cmd_iu *)fcp_req->cmdaddr)->sqe;
|
||||
|
||||
ibmvfc_dbg(evt->vhost, "fc_done: (%x:%x)\n", be16_to_cpu(vfc_cmd->status),
|
||||
be16_to_cpu(vfc_cmd->error));
|
||||
ibmvfc_dbg(evt->vhost, "fc_done: cmdlen: %d, rsplen %d, payload_len %d\n",
|
||||
fcp_req->cmdlen, fcp_req->rsplen, fcp_req->payload_length);
|
||||
|
||||
fcp_req->status = 0;
|
||||
if (!vfc_cmd->status) {
|
||||
fcp_req->rcv_rsplen = NVME_FC_SIZEOF_ZEROS_RSP;
|
||||
fcp_req->transferred_length = fcp_req->payload_length;
|
||||
} else if (be16_to_cpu(vfc_cmd->status) & IBMVFC_FC_NVME_STATUS) {
|
||||
fcp_req->rcv_rsplen = sizeof(struct nvme_fc_ersp_iu);
|
||||
fcp_req->transferred_length = be32_to_cpu(ersp->xfrd_len);
|
||||
if (be16_to_cpu(vfc_cmd->error) & IBMVFC_NVMS_VALID_NODMA_CQE)
|
||||
cqe->command_id = sqe->common.command_id;
|
||||
} else {
|
||||
fcp_req->rcv_rsplen = 0;
|
||||
fcp_req->transferred_length = 0;
|
||||
fcp_req->status = NVME_SC_INTERNAL;
|
||||
}
|
||||
|
||||
fcp_req->done(fcp_req);
|
||||
ibmvfc_free_event(evt);
|
||||
}
|
||||
|
||||
static struct ibmvfc_cmd *ibmvfc_nvme_init_vfc_cmd(struct ibmvfc_event *evt,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
struct nvmefc_fcp_req *fcp_req)
|
||||
{
|
||||
struct ibmvfc_target *tgt = rport->private;
|
||||
struct ibmvfc_cmd *vfc_cmd = &evt->iu.cmd;
|
||||
|
||||
memset(vfc_cmd, 0, sizeof(*vfc_cmd));
|
||||
|
||||
vfc_cmd->resp.va = cpu_to_be64(fcp_req->rspdma);
|
||||
vfc_cmd->resp.len = cpu_to_be32(fcp_req->rsplen);
|
||||
vfc_cmd->frame_type = cpu_to_be32(IBMVFC_NVME_FCP_TYPE);
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_NVMEOF_PROTOCOL);
|
||||
vfc_cmd->payload_len = cpu_to_be32(fcp_req->cmdlen);
|
||||
vfc_cmd->resp_len = cpu_to_be32(fcp_req->rsplen);
|
||||
vfc_cmd->cancel_key = cpu_to_be32((u64)evt);
|
||||
vfc_cmd->target_wwpn = cpu_to_be64(rport->port_name);
|
||||
vfc_cmd->tgt_scsi_id = cpu_to_be64(rport->port_id);
|
||||
vfc_cmd->assoc_id = cpu_to_be64(tgt->assoc_id);
|
||||
|
||||
memcpy(&vfc_cmd->v3nvme.iu, fcp_req->cmdaddr, fcp_req->cmdlen);
|
||||
|
||||
return vfc_cmd;
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_map_sg_list(struct nvmefc_fcp_req *fcp_req,
|
||||
struct srp_direct_buf *md)
|
||||
{
|
||||
int i;
|
||||
struct scatterlist *sg;
|
||||
|
||||
for_each_sg(fcp_req->first_sgl, sg, fcp_req->sg_cnt, i) {
|
||||
md[i].va = cpu_to_be64(sg_dma_address(sg));
|
||||
md[i].len = cpu_to_be32(sg_dma_len(sg));
|
||||
md[i].key = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int ibmvfc_nvme_map_sg_data(struct nvmefc_fcp_req *fcp_req,
|
||||
struct ibmvfc_event *evt,
|
||||
struct ibmvfc_cmd *vfc_cmd)
|
||||
{
|
||||
struct srp_direct_buf *data = &vfc_cmd->ioba;
|
||||
struct ibmvfc_host *vhost = evt->vhost;
|
||||
|
||||
if (!fcp_req->sg_cnt) {
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_NO_MEM_DESC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fcp_req->io_dir == NVMEFC_FCP_WRITE)
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_WRITE);
|
||||
else
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_READ);
|
||||
|
||||
if (fcp_req->sg_cnt == 1) {
|
||||
ibmvfc_nvme_map_sg_list(fcp_req, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
vfc_cmd->flags |= cpu_to_be16(IBMVFC_SCATTERLIST);
|
||||
|
||||
if (!evt->ext_list) {
|
||||
evt->ext_list = dma_pool_alloc(vhost->sg_pool, GFP_ATOMIC,
|
||||
&evt->ext_list_token);
|
||||
|
||||
if (!evt->ext_list)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ibmvfc_nvme_map_sg_list(fcp_req, evt->ext_list);
|
||||
|
||||
data->va = cpu_to_be64(evt->ext_list_token);
|
||||
data->len = cpu_to_be32(fcp_req->sg_cnt * sizeof(struct srp_direct_buf));
|
||||
data->key = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ibmvfc_nvme_fcp_io(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
void *hw_queue_handle,
|
||||
struct nvmefc_fcp_req *fcp_req)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
struct ibmvfc_nvme_qhandle *qhandle = hw_queue_handle;
|
||||
struct ibmvfc_cmd *vfc_cmd;
|
||||
struct ibmvfc_event *evt;
|
||||
int rc;
|
||||
|
||||
ibmvfc_dbg(vhost, "nvme_fcp_io\n");
|
||||
evt = ibmvfc_get_event(qhandle->queue);
|
||||
if (!evt)
|
||||
return -EBUSY;
|
||||
|
||||
evt->hwq = qhandle->index;
|
||||
ibmvfc_dbg(vhost, "vfc-nvme-mq-%d\n", evt->hwq);
|
||||
|
||||
ibmvfc_init_event(evt, ibmvfc_nvme_done, IBMVFC_CMD_FORMAT);
|
||||
evt->fcp_req = fcp_req;
|
||||
fcp_req->private = evt;
|
||||
|
||||
vfc_cmd = ibmvfc_nvme_init_vfc_cmd(evt, rport, fcp_req);
|
||||
|
||||
vfc_cmd->correlation = cpu_to_be64((u64)evt);
|
||||
|
||||
if (likely(!(rc = ibmvfc_nvme_map_sg_data(fcp_req, evt, vfc_cmd))))
|
||||
return ibmvfc_send_event(evt, vhost, 0);
|
||||
|
||||
ibmvfc_free_event(evt);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ibmvfc_init_fcp_abort(struct ibmvfc_event *evt,
|
||||
struct nvmefc_fcp_req *abort_req)
|
||||
{
|
||||
struct ibmvfc_tmf *tmf;
|
||||
struct ibmvfc_event *abt_evt = abort_req->private;
|
||||
struct ibmvfc_target *tgt = abt_evt->tgt;
|
||||
|
||||
tmf = &evt->iu.tmf;
|
||||
memset(tmf, 0, sizeof(*tmf));
|
||||
tmf->common.version = cpu_to_be32(2);
|
||||
tmf->common.opcode = cpu_to_be32(IBMVFC_NVMF_TMF_MAD);
|
||||
tmf->common.length = cpu_to_be16(sizeof(*tmf));
|
||||
tmf->flags = cpu_to_be32(IBMVFC_TMF_ABORT_TASK | IBMVFC_TMF_NVMF_ASSOC);
|
||||
tmf->cancel_key = cpu_to_be32((u64)abt_evt);
|
||||
tmf->my_cancel_key = cpu_to_be32((u64)evt);
|
||||
tmf->target_wwpn = cpu_to_be64(tgt->wwpn);
|
||||
tmf->assoc_id = cpu_to_be64(tgt->assoc_id);
|
||||
tmf->task_tag = cpu_to_be64((u64)abt_evt);
|
||||
|
||||
init_completion(&evt->comp);
|
||||
}
|
||||
|
||||
static void ibmvfc_nvme_fcp_abort(struct nvme_fc_local_port *lport,
|
||||
struct nvme_fc_remote_port *rport,
|
||||
void *hw_queue_handle,
|
||||
struct nvmefc_fcp_req *abort_req)
|
||||
{
|
||||
struct ibmvfc_host *vhost = lport->private;
|
||||
struct ibmvfc_target *tgt = rport->private;
|
||||
struct ibmvfc_event *evt, *abt_evt = abort_req->private;
|
||||
struct ibmvfc_queue *queue;
|
||||
union ibmvfc_iu rsp;
|
||||
unsigned long flags;
|
||||
u16 status = 0;
|
||||
|
||||
if (!abt_evt)
|
||||
return;
|
||||
|
||||
queue = abt_evt->queue;
|
||||
if (!vhost->logged_in || !queue)
|
||||
return;
|
||||
|
||||
evt = ibmvfc_get_event(queue);
|
||||
if (!evt)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(queue->q_lock, flags);
|
||||
kref_get(&tgt->kref);
|
||||
ibmvfc_init_event(evt, ibmvfc_sync_nvme_completion, IBMVFC_MAD_FORMAT);
|
||||
ibmvfc_init_fcp_abort(evt, abort_req);
|
||||
evt->sync_iu = &rsp;
|
||||
|
||||
if (ibmvfc_send_event(evt, vhost, default_timeout))
|
||||
goto out;
|
||||
|
||||
spin_unlock_irqrestore(queue->q_lock, flags);
|
||||
|
||||
wait_for_completion(&evt->comp);
|
||||
status = be16_to_cpu(rsp.mad_common.status);
|
||||
|
||||
spin_lock_irqsave(queue->q_lock, flags);
|
||||
ibmvfc_free_event(evt);
|
||||
out:
|
||||
spin_unlock_irqrestore(queue->q_lock, flags);
|
||||
|
||||
if (status)
|
||||
ibmvfc_dbg(vhost, "fcp_abort: cancel failed with rc=%x\n", status);
|
||||
|
||||
kref_put(&tgt->kref, ibmvfc_release_tgt);
|
||||
}
|
||||
|
||||
static struct nvme_fc_port_template ibmvfc_nvme_fc_transport = {
|
||||
.localport_delete = ibmvfc_nvme_localport_delete,
|
||||
.remoteport_delete = ibmvfc_nvme_remoteport_delete,
|
||||
.create_queue = ibmvfc_nvme_create_queue,
|
||||
.delete_queue = ibmvfc_nvme_delete_queue,
|
||||
.ls_req = ibmvfc_nvme_ls_req,
|
||||
.ls_abort = ibmvfc_nvme_ls_abort,
|
||||
.fcp_io = ibmvfc_nvme_fcp_io,
|
||||
.fcp_abort = ibmvfc_nvme_fcp_abort,
|
||||
.map_queues = NULL,
|
||||
.max_hw_queues = IBMVFC_NVME_HW_QUEUES,
|
||||
.max_sgl_segments = 1024,
|
||||
.max_dif_sgl_segments = 64,
|
||||
.dma_boundary = 0xFFFFFFFF,
|
||||
.local_priv_sz = sizeof(struct ibmvfc_host *),
|
||||
.remote_priv_sz = sizeof(struct ibmvfc_target *),
|
||||
.lsrqst_priv_sz = sizeof(struct ibmvfc_event *),
|
||||
.fcprqst_priv_sz = sizeof(struct ibmvfc_event *),
|
||||
};
|
||||
|
||||
int ibmvfc_nvme_register_remoteport(struct ibmvfc_target *tgt)
|
||||
{
|
||||
struct ibmvfc_host *vhost = tgt->vhost;
|
||||
struct nvme_fc_port_info pinfo;
|
||||
int rc;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NVME_FC))
|
||||
return 0;
|
||||
|
||||
if (!vhost->nvme_local_port) {
|
||||
dev_err(vhost->dev, "Attempt to register NVMe fc remoteport without valid localport\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(&pinfo, 0, sizeof(struct nvme_fc_port_info));
|
||||
pinfo.node_name = tgt->ids.node_name;
|
||||
pinfo.port_name = tgt->ids.port_name;
|
||||
pinfo.port_id = tgt->ids.port_id;
|
||||
pinfo.port_role = FC_PORT_ROLE_NVME_TARGET;
|
||||
|
||||
rc = nvme_fc_register_remoteport(vhost->nvme_local_port, &pinfo,
|
||||
&tgt->nvme_remote_port);
|
||||
|
||||
if (!rc) {
|
||||
ibmvfc_log(vhost, 2, "register_remoteport: traddr=nn-0x%llx:pn-0x%llx PortID:%x\n",
|
||||
pinfo.node_name, pinfo.port_name, pinfo.port_id);
|
||||
tgt->nvme_remote_port->private = tgt;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ibmvfc_nvme_unregister_remoteport(struct ibmvfc_target *tgt)
|
||||
{
|
||||
struct ibmvfc_host *vhost = tgt->vhost;
|
||||
struct nvme_fc_remote_port *rport = tgt->nvme_remote_port;
|
||||
int rc;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NVME_FC))
|
||||
return;
|
||||
|
||||
if (!tgt->nvme_remote_port)
|
||||
return;
|
||||
|
||||
ibmvfc_log(vhost, 2, "unregister_remoteport: traddr=nn-0x%llx:pn-0x%llx PortID:%x\n",
|
||||
rport->node_name, rport->port_name, rport->port_id);
|
||||
init_completion(&tgt->nvme_delete_done);
|
||||
rc = nvme_fc_unregister_remoteport(tgt->nvme_remote_port);
|
||||
|
||||
if (!rc) {
|
||||
wait_for_completion(&tgt->nvme_delete_done);
|
||||
}
|
||||
}
|
||||
|
||||
int ibmvfc_nvme_register(struct ibmvfc_host *vhost)
|
||||
{
|
||||
struct nvme_fc_port_info pinfo;
|
||||
int rc;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NVME_FC))
|
||||
return 0;
|
||||
|
||||
pinfo.node_name = fc_host_node_name(vhost->host);
|
||||
pinfo.port_name = fc_host_port_name(vhost->host);
|
||||
pinfo.port_id = fc_host_port_id(vhost->host);
|
||||
pinfo.port_role = FC_PORT_ROLE_NVME_INITIATOR;
|
||||
pinfo.dev_loss_tmo = 0;
|
||||
|
||||
rc = nvme_fc_register_localport(&pinfo, &ibmvfc_nvme_fc_transport,
|
||||
get_device(vhost->dev),
|
||||
&vhost->nvme_local_port);
|
||||
|
||||
if (!rc) {
|
||||
ibmvfc_log(vhost, 2, "register_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
|
||||
pinfo.node_name, pinfo.port_name, pinfo.port_id);
|
||||
vhost->nvme_local_port->private = vhost;
|
||||
} else {
|
||||
dev_err(vhost->dev, "Failed to register NVMe fc localport (%d)\n", rc);
|
||||
put_device(vhost->dev);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ibmvfc_nvme_unregister(struct ibmvfc_host *vhost)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_NVME_FC))
|
||||
return;
|
||||
|
||||
if (vhost->nvme_local_port) {
|
||||
ibmvfc_log(vhost, 2, "unregister_localport: host-traddr=nn-0x%llx:pn-0x%llx on portID:%x\n",
|
||||
vhost->nvme_local_port->node_name,
|
||||
vhost->nvme_local_port->port_name,
|
||||
vhost->nvme_local_port->port_id);
|
||||
init_completion(&vhost->nvme_delete_done);
|
||||
rc = nvme_fc_unregister_localport(vhost->nvme_local_port);
|
||||
if (!rc) {
|
||||
wait_for_completion(&vhost->nvme_delete_done);
|
||||
} else
|
||||
dev_err(vhost->dev, "Failed to unregister NVMe fc localport (%d)\n", rc);
|
||||
|
||||
put_device(vhost->dev);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* ibmvfc-nvme.h -- IBM Power Virtual Fibre Channel NVMeoF HBA driver
|
||||
*
|
||||
* Written By: Tyrel Datwyler <tyreld@linux.ibm.com>, IBM Corporation
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2026
|
||||
*/
|
||||
|
||||
#ifndef _IBMVFC_NVME_H
|
||||
#define _IBMVFC_NVME_H
|
||||
|
||||
#include <scsi/fc/fc_fs.h>
|
||||
#include <scsi/fc/fc_els.h>
|
||||
#include <linux/nvme-fc-driver.h>
|
||||
#include <linux/nvme.h>
|
||||
#include <linux/nvme-fc.h>
|
||||
|
||||
#include "ibmvfc.h"
|
||||
|
||||
#define IBMVFC_NVME 0
|
||||
#define IBMVFC_NVME_HW_QUEUES 8
|
||||
#define IBMVFC_MAX_NVME_QUEUES 16
|
||||
#define IBMVFC_NVME_CHANNELS 8
|
||||
|
||||
#define IBMVFC_FC4_LS_TIMEOUT 15
|
||||
#define IBMVFC_FC4_LS_CANCEL_TIMEOUT 45
|
||||
#define IBMVFC_FC4_LS_PLUS_CANCEL_TIMEOUT \
|
||||
(IBMVFC_FC4_LS_TIMEOUT + IBMVFC_FC4_LS_CANCEL_TIMEOUT)
|
||||
|
||||
extern unsigned int ibmvfc_debug;
|
||||
|
||||
struct ibmvfc_host;
|
||||
struct ibmvfc_target;
|
||||
struct ibmvfc_queue;
|
||||
|
||||
struct ibmvfc_nvme_qhandle {
|
||||
unsigned int qidx;
|
||||
u16 cpu_id;
|
||||
unsigned long index;
|
||||
struct ibmvfc_queue *queue;
|
||||
};
|
||||
|
||||
int ibmvfc_nvme_register_remoteport(struct ibmvfc_target *tgt);
|
||||
void ibmvfc_nvme_unregister_remoteport(struct ibmvfc_target *tgt);
|
||||
int ibmvfc_nvme_register(struct ibmvfc_host *vhost);
|
||||
void ibmvfc_nvme_unregister(struct ibmvfc_host *vhost);
|
||||
#endif
|
||||
+177
-42
@@ -1,20 +1,27 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/*
|
||||
* ibmvfc.h -- driver for IBM Power Virtual Fibre Channel Adapter
|
||||
*
|
||||
* Written By: Brian King <brking@linux.vnet.ibm.com>, IBM Corporation
|
||||
*
|
||||
* Copyright (C) IBM Corporation, 2008
|
||||
* Copyright (C) IBM Corporation, 2008-2026
|
||||
*/
|
||||
|
||||
#ifndef _IBMVFC_H
|
||||
#define _IBMVFC_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/types.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/viosrp.h>
|
||||
#include <linux/nvme.h>
|
||||
#include <linux/nvme-fc.h>
|
||||
|
||||
#define IBMVFC_NAME "ibmvfc"
|
||||
#include "ibmvfc-nvme.h"
|
||||
|
||||
#define IBMVFC_NAME "ibmvfc"
|
||||
#define IBMVFC_DRIVER_VERSION "1.0.11"
|
||||
#define IBMVFC_DRIVER_DATE "(April 12, 2013)"
|
||||
|
||||
@@ -92,6 +99,7 @@ enum ibmvfc_cmd_status_flags {
|
||||
IBMVFC_FC_SCSI_ERROR = 0x0008,
|
||||
IBMVFC_HW_EVENT_LOGGED = 0x0010,
|
||||
IBMVFC_VIOS_LOGGED = 0x0020,
|
||||
IBMVFC_FC_NVME_STATUS = 0x0040,
|
||||
};
|
||||
|
||||
enum ibmvfc_fabric_mapped_errors {
|
||||
@@ -124,20 +132,37 @@ enum ibmvfc_vios_errors {
|
||||
IBMVFC_COMMAND_FAILED = 0x8000,
|
||||
};
|
||||
|
||||
enum ibmvfc_fc_nvme_errors {
|
||||
IBMVFC_NVMS_VALID_ERSP = 0x0001,
|
||||
IBMVFC_NVMS_VALID_NODMA_CQE = 0x0002,
|
||||
};
|
||||
|
||||
enum ibmvfc_mad_types {
|
||||
IBMVFC_NPIV_LOGIN = 0x0001,
|
||||
IBMVFC_DISC_TARGETS = 0x0002,
|
||||
IBMVFC_DISC_TARGETS = 0x0002,
|
||||
IBMVFC_DISC_NVMF_TARGETS = 0x0003,
|
||||
IBMVFC_PORT_LOGIN = 0x0004,
|
||||
IBMVFC_PROCESS_LOGIN = 0x0008,
|
||||
IBMVFC_QUERY_TARGET = 0x0010,
|
||||
IBMVFC_NVMF_PORT_LOGIN = 0x0005,
|
||||
IBMVFC_PROCESS_LOGIN = 0x0008,
|
||||
IBMVFC_NVMF_PROCESS_LOGIN = 0x0009,
|
||||
IBMVFC_QUERY_TARGET = 0x0010,
|
||||
IBMVFC_NVMF_QUERY_TARGET = 0x0011,
|
||||
IBMVFC_MOVE_LOGIN = 0x0020,
|
||||
IBMVFC_IMPLICIT_LOGOUT = 0x0040,
|
||||
IBMVFC_PASSTHRU = 0x0200,
|
||||
IBMVFC_TMF_MAD = 0x0100,
|
||||
IBMVFC_NPIV_LOGOUT = 0x0800,
|
||||
IBMVFC_CHANNEL_ENQUIRY = 0x1000,
|
||||
IBMVFC_CHANNEL_SETUP = 0x2000,
|
||||
IBMVFC_CONNECTION_INFO = 0x4000,
|
||||
IBMVFC_NVMF_MOVE_LOGIN = 0x0021,
|
||||
IBMVFC_IMPLICIT_LOGOUT = 0x0040,
|
||||
IBMVFC_NVMF_IMPLICIT_LOGOUT = 0x0041,
|
||||
IBMVFC_RNID = 0x0080,
|
||||
IBMVFC_NVMF_RNID = 0x0081,
|
||||
IBMVFC_TMF_MAD = 0x0100,
|
||||
IBMVFC_NVMF_TMF_MAD = 0x0101,
|
||||
IBMVFC_PASSTHRU = 0x0200,
|
||||
IBMVFC_NVMF_PASSTHRU = 0x0201,
|
||||
IBMVFC_NPIV_LOGOUT = 0x0800,
|
||||
IBMVFC_CHANNEL_ENQUIRY = 0x1000,
|
||||
IBMVFC_CHANNEL_SETUP = 0x2000,
|
||||
IBMVFC_CONNECTION_INFO = 0x4000,
|
||||
IBMVFC_FABRIC_LOGIN = 0x8000,
|
||||
IBMVFC_NVMF_FABRIC_LOGIN = 0x8001,
|
||||
};
|
||||
|
||||
struct ibmvfc_mad_common {
|
||||
@@ -175,11 +200,16 @@ struct ibmvfc_npiv_login {
|
||||
#define IBMVFC_FLUSH_ON_HALT 0x02
|
||||
__be32 max_cmds;
|
||||
__be64 capabilities;
|
||||
#define IBMVFC_CAN_MIGRATE 0x01
|
||||
#define IBMVFC_CAN_USE_CHANNELS 0x02
|
||||
#define IBMVFC_CAN_HANDLE_FPIN 0x04
|
||||
#define IBMVFC_CAN_USE_MAD_VERSION 0x08
|
||||
#define IBMVFC_CAN_SEND_VF_WWPN 0x10
|
||||
#define IBMVFC_CAN_MIGRATE 0x001
|
||||
#define IBMVFC_CAN_USE_CHANNELS 0x002
|
||||
#define IBMVFC_CAN_HANDLE_FPIN 0x004
|
||||
#define IBMVFC_CAN_USE_MAD_VERSION 0x008
|
||||
#define IBMVFC_CAN_SEND_VF_WWPN 0x010
|
||||
#define IBMVFC_YES_NVMEOF 0x020
|
||||
#define IBMVFC_YES_SCSI 0x040
|
||||
#define IBMVFC_CAN_USE_WWPN_ALL 0x080
|
||||
#define IBMVFC_USE_ASYNC_SUBQ 0x100
|
||||
#define IBMVFC_CAN_USE_NOOP_CMD 0x200
|
||||
__be64 node_name;
|
||||
struct srp_direct_buf async;
|
||||
u8 partition_name[IBMVFC_MAX_NAME];
|
||||
@@ -219,13 +249,18 @@ struct ibmvfc_npiv_login_resp {
|
||||
__be16 error;
|
||||
__be32 flags;
|
||||
#define IBMVFC_NATIVE_FC 0x01
|
||||
__be32 reserved;
|
||||
__be32 possible_nports;
|
||||
__be64 capabilities;
|
||||
#define IBMVFC_CAN_FLUSH_ON_HALT 0x08
|
||||
#define IBMVFC_CAN_SUPPRESS_ABTS 0x10
|
||||
#define IBMVFC_MAD_VERSION_CAP 0x20
|
||||
#define IBMVFC_HANDLE_VF_WWPN 0x40
|
||||
#define IBMVFC_CAN_SUPPORT_CHANNELS 0x80
|
||||
#define IBMVFC_CAN_FLUSH_ON_HALT 0x0008
|
||||
#define IBMVFC_CAN_SUPPRESS_ABTS 0x0010
|
||||
#define IBMVFC_MAD_VERSION_CAP 0x0020
|
||||
#define IBMVFC_HANDLE_VF_WWPN 0x0040
|
||||
#define IBMVFC_CAN_SUPPORT_CHANNELS 0x0080
|
||||
#define IBMVFC_SUPPORT_NVMEOF 0x0100
|
||||
#define IBMVFC_SUPPORT_SCSI 0x0200
|
||||
#define IBMVFC_SUPPORT_WWPN_ALL 0x0400
|
||||
#define IBMVFC_ASYNC_SUBQ 0x0800
|
||||
#define IBMVFC_SUPPORT_NOOP_CMD 0x1000
|
||||
__be32 max_cmds;
|
||||
__be32 scsi_id_sz;
|
||||
__be64 max_dma_len;
|
||||
@@ -238,7 +273,7 @@ struct ibmvfc_npiv_login_resp {
|
||||
u8 port_loc_code[IBMVFC_MAX_NAME];
|
||||
u8 drc_name[IBMVFC_MAX_NAME];
|
||||
struct ibmvfc_service_parms service_parms;
|
||||
__be64 reserved2;
|
||||
__be64 reserved;
|
||||
} __packed __aligned(8);
|
||||
|
||||
union ibmvfc_npiv_login_data {
|
||||
@@ -246,6 +281,17 @@ union ibmvfc_npiv_login_data {
|
||||
struct ibmvfc_npiv_login_resp resp;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_fabric_login_mad {
|
||||
struct ibmvfc_mad_common common;
|
||||
__be64 flags;
|
||||
__be64 capabilities;
|
||||
__be64 nport_id;
|
||||
__be16 status;
|
||||
__be16 error;
|
||||
__be32 reserved;
|
||||
__be64 reserved2[16];
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_discover_targets_entry {
|
||||
__be32 scsi_id;
|
||||
__be32 pad;
|
||||
@@ -287,6 +333,7 @@ enum ibmvfc_fc_type {
|
||||
IBMVFC_FABRIC_BUSY = 0x04,
|
||||
IBMVFC_PORT_BUSY = 0x05,
|
||||
IBMVFC_BASIC_REJECT = 0x06,
|
||||
IBMVFC_FC4_LS_REJECT = 0x07,
|
||||
};
|
||||
|
||||
enum ibmvfc_gs_explain {
|
||||
@@ -334,6 +381,7 @@ struct ibmvfc_move_login {
|
||||
struct ibmvfc_prli_svc_parms {
|
||||
u8 type;
|
||||
#define IBMVFC_SCSI_FCP_TYPE 0x08
|
||||
#define IBMVFC_NVME_FCP_TYPE 0x28
|
||||
u8 type_ext;
|
||||
__be16 flags;
|
||||
#define IBMVFC_PRLI_ORIG_PA_VALID 0x8000
|
||||
@@ -349,6 +397,11 @@ struct ibmvfc_prli_svc_parms {
|
||||
#define IBMVFC_PRLI_TARGET_FUNC 0x00000010
|
||||
#define IBMVFC_PRLI_READ_FCP_XFER_RDY_DISABLED 0x00000002
|
||||
#define IBMVFC_PRLI_WR_FCP_XFER_RDY_DISABLED 0x00000001
|
||||
#define IBMVFC_PRLI_NVME_PI_CTRL 0x00000200
|
||||
#define IBMVFC_PRLI_NVME_SLER 0x00000100
|
||||
#define IBMVFC_PRLI_NVME_INITIATOR 0x00000020
|
||||
#define IBMVFC_PRLI_NVME_TARGET 0x00000010
|
||||
#define IBMVFC_PRLI_NVME_DISCOVERY 0x00000008
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct ibmvfc_process_login {
|
||||
@@ -377,20 +430,27 @@ struct ibmvfc_query_tgt {
|
||||
struct ibmvfc_implicit_logout {
|
||||
struct ibmvfc_mad_common common;
|
||||
__be64 old_scsi_id;
|
||||
__be64 reserved[2];
|
||||
__be64 reserved[8];
|
||||
__be64 target_wwpn;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_tmf {
|
||||
struct ibmvfc_mad_common common;
|
||||
__be64 scsi_id;
|
||||
struct scsi_lun lun;
|
||||
union {
|
||||
struct scsi_lun lun;
|
||||
__be64 assoc_id;
|
||||
};
|
||||
__be32 flags;
|
||||
#define IBMVFC_TMF_ABORT_TASK 0x02
|
||||
#define IBMVFC_TMF_ABORT_TASK_SET 0x04
|
||||
#define IBMVFC_TMF_LUN_RESET 0x10
|
||||
#define IBMVFC_TMF_TGT_RESET 0x20
|
||||
#define IBMVFC_TMF_LUA_VALID 0x40
|
||||
#define IBMVFC_TMF_SUPPRESS_ABTS 0x80
|
||||
#define IBMVFC_TMF_ABORT_TASK 0x002
|
||||
#define IBMVFC_TMF_ABORT_TASK_SET 0x004
|
||||
#define IBMVFC_TMF_LUN_RESET 0x010
|
||||
#define IBMVFC_TMF_TGT_RESET 0x020
|
||||
#define IBMVFC_TMF_LUA_VALID 0x040
|
||||
#define IBMVFC_TMF_SUPPRESS_ABTS 0x080
|
||||
#define IBMVFC_TMF_NVMF_ASSOC 0x100
|
||||
#define IBMVFC_TMF_NVMF_TARGET 0x200
|
||||
#define IBMVFC_TMF_BITMASK_VALID 0x400
|
||||
__be32 cancel_key;
|
||||
__be32 my_cancel_key;
|
||||
__be32 pad;
|
||||
@@ -446,6 +506,8 @@ enum ibmvfc_cmd_flags {
|
||||
IBMVFC_WRITE = 0x0008,
|
||||
IBMVFC_TMF = 0x0080,
|
||||
IBMVFC_CLASS_3_ERR = 0x0100,
|
||||
IBMVFC_NVMEOF_PROTOCOL = 0x0200,
|
||||
IBMVFC_NVMF_SLER = 0x0400,
|
||||
};
|
||||
|
||||
enum ibmvfc_fc_task_attr {
|
||||
@@ -493,7 +555,7 @@ struct ibmvfc_cmd {
|
||||
__be64 tgt_scsi_id;
|
||||
__be64 tag;
|
||||
__be64 target_wwpn;
|
||||
__be64 reserved3;
|
||||
__be64 assoc_id;
|
||||
union {
|
||||
struct {
|
||||
struct ibmvfc_fcp_cmd_iu iu;
|
||||
@@ -504,6 +566,15 @@ struct ibmvfc_cmd {
|
||||
struct ibmvfc_fcp_cmd_iu iu;
|
||||
struct ibmvfc_fcp_rsp rsp;
|
||||
} v2;
|
||||
struct {
|
||||
__be64 reserved5[4];
|
||||
struct ibmvfc_fcp_cmd_iu iu;
|
||||
struct ibmvfc_fcp_rsp rsp;
|
||||
} v3scsi;
|
||||
struct {
|
||||
__be64 reserved[4];
|
||||
struct nvme_fc_cmd_iu iu;
|
||||
} v3nvme;
|
||||
};
|
||||
} __packed __aligned(8);
|
||||
|
||||
@@ -522,6 +593,9 @@ struct ibmvfc_passthru_iu {
|
||||
__be32 flags;
|
||||
#define IBMVFC_FC_ELS 0x01
|
||||
#define IBMVFC_FC_CT_IU 0x02
|
||||
#define IBMVFC_PT_PRLI 0x04
|
||||
#define IBMVFC_FC4_LS_OTH 0x08
|
||||
#define IBMVFC_FC4_LS_DSC_CTRL 0x10
|
||||
__be32 cancel_key;
|
||||
#define IBMVFC_PASSTHRU_CANCEL_KEY 0x80000000
|
||||
#define IBMVFC_INTERNAL_CANCEL_KEY 0x80000001
|
||||
@@ -549,9 +623,9 @@ struct ibmvfc_channel_enquiry {
|
||||
#define IBMVFC_SUPPORT_VARIABLE_SUBQ_MSG 0x02
|
||||
#define IBMVFC_NO_N_TO_M_CHANNELS_SUPPORT 0x04
|
||||
__be32 num_scsi_subq_channels;
|
||||
__be32 num_nvmeof_subq_channels;
|
||||
__be32 num_nvme_subq_channels;
|
||||
__be32 num_scsi_vas_channels;
|
||||
__be32 num_nvmeof_vas_channels;
|
||||
__be32 num_nvme_vas_channels;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_channel_setup_mad {
|
||||
@@ -559,7 +633,7 @@ struct ibmvfc_channel_setup_mad {
|
||||
struct srp_direct_buf buffer;
|
||||
} __packed __aligned(8);
|
||||
|
||||
#define IBMVFC_MAX_CHANNELS 502
|
||||
#define IBMVFC_MAX_CHANNELS 501
|
||||
|
||||
struct ibmvfc_channel_setup {
|
||||
__be32 flags;
|
||||
@@ -568,12 +642,13 @@ struct ibmvfc_channel_setup {
|
||||
#define IBMVFC_CHANNELS_CANCELED 0x04
|
||||
__be32 reserved;
|
||||
__be32 num_scsi_subq_channels;
|
||||
__be32 num_nvmeof_subq_channels;
|
||||
__be32 num_nvme_subq_channels;
|
||||
__be32 num_scsi_vas_channels;
|
||||
__be32 num_nvmeof_vas_channels;
|
||||
__be32 num_nvme_vas_channels;
|
||||
struct srp_direct_buf buffer;
|
||||
__be64 reserved2[5];
|
||||
__be64 channel_handles[IBMVFC_MAX_CHANNELS];
|
||||
__be64 async_sub_crq_handle;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_connection_info {
|
||||
@@ -620,7 +695,8 @@ struct ibmvfc_trace_entry {
|
||||
|
||||
enum ibmvfc_crq_formats {
|
||||
IBMVFC_CMD_FORMAT = 0x01,
|
||||
IBMVFC_ASYNC_EVENT = 0x02,
|
||||
IBMVFC_ASYNC_EVENT = 0x02,
|
||||
IBMVFC_NOOP = 0x03,
|
||||
IBMVFC_MAD_FORMAT = 0x04,
|
||||
};
|
||||
|
||||
@@ -639,6 +715,9 @@ enum ibmvfc_async_event {
|
||||
IBMVFC_AE_RESUME = 0x0800,
|
||||
IBMVFC_AE_ADAPTER_FAILED = 0x1000,
|
||||
IBMVFC_AE_FPIN = 0x2000,
|
||||
IBMVFC_NVME_DISCONNECT = 0x4000,
|
||||
IBMVFC_NVMEOF_PROTO_AVAIL = 0x40000000,
|
||||
IBMVFC_SCSI_PROTO_AVAIL = 0x80000000,
|
||||
};
|
||||
|
||||
struct ibmvfc_async_desc {
|
||||
@@ -683,13 +762,30 @@ struct ibmvfc_async_crq {
|
||||
volatile __be64 scsi_id;
|
||||
volatile __be64 wwpn;
|
||||
volatile __be64 node_name;
|
||||
__be64 reserved;
|
||||
__be64 assoc_id;
|
||||
} __packed __aligned(8);
|
||||
|
||||
struct ibmvfc_async_sub_crq {
|
||||
volatile u8 valid;
|
||||
u8 flags;
|
||||
#define IBMVFC_ASYNC_ID_IS_ASSOC_ID 0x01
|
||||
u8 link_state;
|
||||
u8 fpin_status;
|
||||
__be16 event;
|
||||
__be16 pad;
|
||||
__be64 wwpn;
|
||||
__be64 nport_id;
|
||||
union {
|
||||
__be64 node_name;
|
||||
__be64 assoc_id;
|
||||
} id;
|
||||
} __packed __aligned(8);
|
||||
|
||||
union ibmvfc_iu {
|
||||
struct ibmvfc_mad_common mad_common;
|
||||
struct ibmvfc_npiv_login_mad npiv_login;
|
||||
struct ibmvfc_npiv_logout_mad npiv_logout;
|
||||
struct ibmvfc_fabric_login_mad fabric_login;
|
||||
struct ibmvfc_discover_targets discover_targets;
|
||||
struct ibmvfc_port_login plogi;
|
||||
struct ibmvfc_process_login prli;
|
||||
@@ -728,6 +824,7 @@ struct ibmvfc_target {
|
||||
u64 scsi_id;
|
||||
u64 wwpn;
|
||||
u64 new_scsi_id;
|
||||
u64 assoc_id;
|
||||
struct fc_rport *rport;
|
||||
int target_id;
|
||||
enum ibmvfc_target_action action;
|
||||
@@ -743,6 +840,8 @@ struct ibmvfc_target {
|
||||
void (*job_step) (struct ibmvfc_target *);
|
||||
struct timer_list timer;
|
||||
struct kref kref;
|
||||
struct completion nvme_delete_done;
|
||||
struct nvme_fc_remote_port *nvme_remote_port;
|
||||
};
|
||||
|
||||
/* a unit of work for the hosting partition */
|
||||
@@ -753,6 +852,8 @@ struct ibmvfc_event {
|
||||
struct ibmvfc_queue *queue;
|
||||
struct ibmvfc_target *tgt;
|
||||
struct scsi_cmnd *cmnd;
|
||||
struct nvmefc_ls_req *ls_req;
|
||||
struct nvmefc_fcp_req *fcp_req;
|
||||
atomic_t free;
|
||||
atomic_t active;
|
||||
union ibmvfc_iu *xfer_iu;
|
||||
@@ -828,6 +929,8 @@ struct ibmvfc_channels {
|
||||
unsigned int active_queues;
|
||||
unsigned int desired_queues;
|
||||
unsigned int max_queues;
|
||||
int num_targets;
|
||||
struct list_head targets;
|
||||
int disc_buf_sz;
|
||||
struct ibmvfc_discover_targets_entry *disc_buf;
|
||||
dma_addr_t disc_buf_dma;
|
||||
@@ -871,8 +974,6 @@ struct ibmvfc_host {
|
||||
#define IBMVFC_TRACE_SIZE (sizeof(struct ibmvfc_trace_entry) * IBMVFC_NUM_TRACE_ENTRIES)
|
||||
struct ibmvfc_trace_entry *trace;
|
||||
atomic_t trace_index;
|
||||
int num_targets;
|
||||
struct list_head targets;
|
||||
struct list_head purge;
|
||||
struct device *dev;
|
||||
struct dma_pool *sg_pool;
|
||||
@@ -880,6 +981,7 @@ struct ibmvfc_host {
|
||||
struct ibmvfc_queue crq;
|
||||
struct ibmvfc_queue async_crq;
|
||||
struct ibmvfc_channels scsi_scrqs;
|
||||
struct ibmvfc_channels nvme_scrqs;
|
||||
struct ibmvfc_npiv_login login_info;
|
||||
union ibmvfc_npiv_login_data *login_buf;
|
||||
dma_addr_t login_buf_dma;
|
||||
@@ -888,6 +990,7 @@ struct ibmvfc_host {
|
||||
int log_level;
|
||||
struct mutex passthru_mutex;
|
||||
unsigned int max_vios_scsi_channels;
|
||||
unsigned int max_vios_nvme_channels;
|
||||
int task_set;
|
||||
int init_retries;
|
||||
int discovery_threads;
|
||||
@@ -899,6 +1002,9 @@ struct ibmvfc_host {
|
||||
unsigned int mq_enabled:1;
|
||||
unsigned int using_channels:1;
|
||||
unsigned int do_enquiry:1;
|
||||
unsigned int nvme_enabled:1;
|
||||
unsigned int do_scsi_login:1;
|
||||
unsigned int do_nvme_login:1;
|
||||
unsigned int aborting_passthru:1;
|
||||
unsigned int scan_complete:1;
|
||||
int scan_timeout;
|
||||
@@ -914,8 +1020,37 @@ struct ibmvfc_host {
|
||||
struct work_struct rport_add_work_q;
|
||||
wait_queue_head_t init_wait_q;
|
||||
wait_queue_head_t work_wait_q;
|
||||
struct nvme_fc_local_port *nvme_local_port;
|
||||
struct completion nvme_delete_done;
|
||||
};
|
||||
|
||||
struct ibmvfc_event *__ibmvfc_get_event(struct ibmvfc_queue *queue, int reserved);
|
||||
#define ibmvfc_get_event(queue) __ibmvfc_get_event(queue, 0)
|
||||
#define ibmvfc_get_reserved_event(queue) __ibmvfc_get_event(queue, 1)
|
||||
|
||||
void ibmvfc_init_event(struct ibmvfc_event *evt, void (*done) (struct ibmvfc_event *), u8 format);
|
||||
void ibmvfc_free_event(struct ibmvfc_event *evt);
|
||||
void ibmvfc_release_tgt(struct kref *kref);
|
||||
int ibmvfc_send_event(struct ibmvfc_event *evt, struct ibmvfc_host *vhost, unsigned long timeout);
|
||||
const char *ibmvfc_get_cmd_error(u16 status, u16 error);
|
||||
|
||||
static inline int ibmvfc_check_caps(struct ibmvfc_host *vhost, unsigned long cap_flags)
|
||||
{
|
||||
u64 host_caps = be64_to_cpu(vhost->login_buf->resp.capabilities);
|
||||
|
||||
return (host_caps & cap_flags) ? 1 : 0;
|
||||
}
|
||||
|
||||
static inline struct ibmvfc_host *ibmvfc_channels_to_vhost(struct ibmvfc_channels *channels)
|
||||
{
|
||||
if (channels->protocol == IBMVFC_PROTO_SCSI)
|
||||
return container_of(channels, struct ibmvfc_host, scsi_scrqs);
|
||||
else if (channels->protocol == IBMVFC_PROTO_NVME)
|
||||
return container_of(channels, struct ibmvfc_host, nvme_scrqs);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define DBG_CMD(CMD) do { if (ibmvfc_debug) CMD; } while (0)
|
||||
|
||||
#define tgt_dbg(t, fmt, ...) \
|
||||
|
||||
@@ -193,21 +193,7 @@ typedef enum {
|
||||
|
||||
#define SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_SHIFT 18
|
||||
#define SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK 0x001C0000
|
||||
#define scu_get_command_request_subtype(x) \
|
||||
((x) & SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK)
|
||||
|
||||
#define SCU_CONTEXT_COMMAND_REQUEST_FULLTYPE_MASK \
|
||||
(\
|
||||
SCU_CONTEXT_COMMAND_REQUEST_TYPE_MASK \
|
||||
| SCU_CONTEXT_COMMAND_REQUEST_SUBTYPE_MASK \
|
||||
)
|
||||
#define scu_get_command_request_full_type(x) \
|
||||
((x) & SCU_CONTEXT_COMMAND_REQUEST_FULLTYPE_MASK)
|
||||
|
||||
#define SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_SHIFT 16
|
||||
#define SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_MASK 0x00010000
|
||||
#define scu_get_command_protocl_engine_group(x) \
|
||||
((x) & SCU_CONTEXT_COMMAND_PROTOCOL_ENGINE_GROUP_MASK)
|
||||
|
||||
#define SCU_CONTEXT_COMMAND_LOGICAL_PORT_SHIFT 12
|
||||
#define SCU_CONTEXT_COMMAND_LOGICAL_PORT_MASK 0x00007000
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
config SCSI_LEAPRAID
|
||||
tristate "LeapIO RAID Adapter"
|
||||
depends on PCI && SCSI
|
||||
select SCSI_SAS_ATTRS
|
||||
help
|
||||
This driver supports LeapIO PCIe-based storage
|
||||
and RAID controllers.
|
||||
|
||||
<http://www.leap-io.com>
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
resulting kernel module will be named leapraid.
|
||||
@@ -0,0 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the LEAPRAID drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_SCSI_LEAPRAID) += leapraid.o
|
||||
leapraid-objs += leapraid_func.o \
|
||||
leapraid_os.o \
|
||||
leapraid_transport.o \
|
||||
leapraid_app.o
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,803 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2026 LeapIO Tech Inc.
|
||||
*
|
||||
* LeapRAID storage and RAID controller driver.
|
||||
*/
|
||||
#include <linux/compat.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
#include "leapraid_func.h"
|
||||
|
||||
/* IOCTL device file name. */
|
||||
#define LEAPRAID_DEV_NAME "leapraid_ctl"
|
||||
|
||||
/* IOCTL version. */
|
||||
#define LEAPRAID_IOCTL_VERSION 0x07
|
||||
|
||||
/* IOCTL commands. */
|
||||
#define LEAPRAID_ADAPTER_INFO 17
|
||||
#define LEAPRAID_COMMAND 20
|
||||
#define LEAPRAID_EVENTQUERY 21
|
||||
#define LEAPRAID_EVENTREPORT 23
|
||||
|
||||
/**
|
||||
* struct leapraid_ioctl_header - IOCTL command header
|
||||
*
|
||||
* @adapter_id : Adapter identifier.
|
||||
* @port_number: Port identifier.
|
||||
* @max_data_size: Maximum data size for transfer.
|
||||
*/
|
||||
struct leapraid_ioctl_header {
|
||||
u32 adapter_id;
|
||||
u32 port_number;
|
||||
u32 max_data_size;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct leapraid_ioctl_diag_reset - Diagnostic reset request
|
||||
*
|
||||
* @hdr: Common IOCTL header.
|
||||
*/
|
||||
struct leapraid_ioctl_diag_reset {
|
||||
struct leapraid_ioctl_header hdr;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct leapraid_ioctl_pci_info - PCI device information
|
||||
*
|
||||
* @u: Union holding PCI bus/device/function information.
|
||||
* @u.bits.dev: PCI device number.
|
||||
* @u.bits.func: PCI function number.
|
||||
* @u.bits.bus: PCI bus number.
|
||||
* @u.word: Combined representation of PCI BDF.
|
||||
* @seg_id: PCI segment identifier.
|
||||
*/
|
||||
struct leapraid_ioctl_pci_info {
|
||||
union {
|
||||
struct {
|
||||
u32 dev:5;
|
||||
u32 func:3;
|
||||
u32 bus:24;
|
||||
} bits;
|
||||
u32 word;
|
||||
} u;
|
||||
u32 seg_id;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct leapraid_ioctl_adapter_info - Adapter information for IOCTL
|
||||
*
|
||||
* @hdr: IOCTL header.
|
||||
* @adapter_type: Adapter type identifier.
|
||||
* @port_number: Port number.
|
||||
* @pci_id: PCI device ID.
|
||||
* @revision: Revision number.
|
||||
* @sub_dev: Subsystem device ID.
|
||||
* @sub_vendor: Subsystem vendor ID.
|
||||
* @r0: Reserved.
|
||||
* @fw_ver: Firmware version.
|
||||
* @bios_ver: BIOS version.
|
||||
* @driver_ver: Driver version.
|
||||
* @r1: Reserved.
|
||||
* @scsi_id: SCSI ID.
|
||||
* @r2: Reserved.
|
||||
* @pci_info: PCI information structure.
|
||||
*/
|
||||
struct leapraid_ioctl_adapter_info {
|
||||
struct leapraid_ioctl_header hdr;
|
||||
u32 adapter_type;
|
||||
u32 port_number;
|
||||
u32 pci_id;
|
||||
u32 revision;
|
||||
u32 sub_dev;
|
||||
u32 sub_vendor;
|
||||
u32 r0;
|
||||
u32 fw_ver;
|
||||
u32 bios_ver;
|
||||
u8 driver_ver[32];
|
||||
u8 r1;
|
||||
u8 scsi_id;
|
||||
u16 r2;
|
||||
struct leapraid_ioctl_pci_info pci_info;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct leapraid_ioctl_command - IOCTL command structure
|
||||
*
|
||||
* @hdr: IOCTL header.
|
||||
* @timeout: Command timeout.
|
||||
* @rep_msg_buf_ptr: User pointer to reply message buffer.
|
||||
* @c2h_buf_ptr: User pointer to card-to-host data buffer.
|
||||
* @h2c_buf_ptr: User pointer to host-to-card data buffer.
|
||||
* @sense_data_ptr: User pointer to sense data buffer.
|
||||
* @max_rep_bytes: Maximum reply bytes.
|
||||
* @c2h_size: Card-to-host data size.
|
||||
* @h2c_size: Host-to-card data size.
|
||||
* @max_sense_bytes: Maximum sense data bytes.
|
||||
* @data_sge_offset: Data SGE offset.
|
||||
* @mf: Message frame data (flexible array).
|
||||
*/
|
||||
struct leapraid_ioctl_command {
|
||||
struct leapraid_ioctl_header hdr;
|
||||
u32 timeout;
|
||||
void __user *rep_msg_buf_ptr;
|
||||
void __user *c2h_buf_ptr;
|
||||
void __user *h2c_buf_ptr;
|
||||
void __user *sense_data_ptr;
|
||||
u32 max_rep_bytes;
|
||||
u32 c2h_size;
|
||||
u32 h2c_size;
|
||||
u32 max_sense_bytes;
|
||||
u32 data_sge_offset;
|
||||
u8 mf[];
|
||||
};
|
||||
|
||||
static int leapraid_ctl_validate_sge_offset(struct leapraid_adapter *adapter,
|
||||
const struct leapraid_req *req,
|
||||
u32 offset_bytes,
|
||||
size_t h2c_size,
|
||||
size_t c2h_size)
|
||||
{
|
||||
size_t sge_bytes;
|
||||
|
||||
switch (req->func) {
|
||||
case LEAPRAID_FUNC_SCSIIO:
|
||||
case LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH:
|
||||
case LEAPRAID_FUNC_SMP_PASSTHROUGH:
|
||||
case LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH:
|
||||
case LEAPRAID_FUNC_FW_DOWNLOAD:
|
||||
case LEAPRAID_FUNC_FW_UPLOAD:
|
||||
sge_bytes = LEAPRAID_IEEE_SGE64_ENTRY_SIZE;
|
||||
break;
|
||||
default:
|
||||
sge_bytes = adapter->adapter_attr.use_32_dma_mask ?
|
||||
sizeof(struct leapraid_sge_simple32) :
|
||||
sizeof(struct leapraid_sge_simple64);
|
||||
break;
|
||||
}
|
||||
|
||||
if (h2c_size && c2h_size)
|
||||
sge_bytes *= 2;
|
||||
|
||||
if (offset_bytes > LEAPRAID_REQUEST_SIZE - sge_bytes) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Invalid offset_bytes=%u for func=0x%x\n",
|
||||
__func__, offset_bytes, req->func);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct leapraid_adapter *leapraid_ctl_lookup_adapter(int adapter_id)
|
||||
{
|
||||
struct leapraid_adapter *adapter;
|
||||
struct Scsi_Host *shost;
|
||||
|
||||
spin_lock(&leapraid_adapter_lock);
|
||||
list_for_each_entry(adapter, &leapraid_adapter_list, list) {
|
||||
if (adapter->adapter_attr.id == adapter_id) {
|
||||
if (READ_ONCE(adapter->access_ctrl.host_removing))
|
||||
break;
|
||||
shost = adapter->shost;
|
||||
if (!shost || !scsi_host_get(shost))
|
||||
break;
|
||||
spin_unlock(&leapraid_adapter_lock);
|
||||
return adapter;
|
||||
}
|
||||
}
|
||||
spin_unlock(&leapraid_adapter_lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void leapraid_ctl_put_adapter(struct leapraid_adapter *adapter)
|
||||
{
|
||||
if (adapter && adapter->shost)
|
||||
scsi_host_put(adapter->shost);
|
||||
}
|
||||
|
||||
static void leapraid_ctl_scsiio_cmd(struct leapraid_adapter *adapter,
|
||||
void *ctl_sp_mpi_req,
|
||||
u16 taskid,
|
||||
dma_addr_t h2c_dma_addr, size_t h2c_size,
|
||||
dma_addr_t c2h_dma_addr, size_t c2h_size,
|
||||
u16 dev_hdl, void *psge)
|
||||
{
|
||||
struct leapraid_mpi_scsiio_req *scsiio_request = ctl_sp_mpi_req;
|
||||
|
||||
scsiio_request->sense_buffer_len = SCSI_SENSE_BUFFERSIZE;
|
||||
scsiio_request->sense_buffer_low_add =
|
||||
leapraid_get_sense_buffer_dma(adapter, taskid);
|
||||
memset(&adapter->driver_cmds.ctl_cmd.sense,
|
||||
0, SCSI_SENSE_BUFFERSIZE);
|
||||
leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr,
|
||||
h2c_size, c2h_dma_addr, c2h_size);
|
||||
if (scsiio_request->func == LEAPRAID_FUNC_SCSIIO)
|
||||
leapraid_fire_scsi_io(adapter, taskid, dev_hdl);
|
||||
else
|
||||
leapraid_fire_task(adapter, taskid);
|
||||
}
|
||||
|
||||
static int leapraid_ctl_smp_passthrough_cmd(struct leapraid_adapter *adapter,
|
||||
void *ctl_sp_req,
|
||||
u16 taskid,
|
||||
dma_addr_t h2c_dma_addr,
|
||||
size_t h2c_size,
|
||||
dma_addr_t c2h_dma_addr,
|
||||
size_t c2h_size,
|
||||
void *psge, void *h2c)
|
||||
{
|
||||
struct leapraid_smp_passthrough_req *smp_pt_req = ctl_sp_req;
|
||||
u8 *data;
|
||||
|
||||
if (!adapter->adapter_attr.enable_mp)
|
||||
smp_pt_req->physical_port = LEAPRAID_DISABLE_MP_PORT_ID;
|
||||
if (smp_pt_req->passthrough_flg & LEAPRAID_SMP_PT_FLAG_SGL_PTR)
|
||||
data = (u8 *)&smp_pt_req->sgl;
|
||||
else
|
||||
data = h2c;
|
||||
|
||||
if (!(smp_pt_req->passthrough_flg & LEAPRAID_SMP_PT_FLAG_SGL_PTR) &&
|
||||
h2c_size <= 10) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Invalid request size=%zu\n",
|
||||
__func__, h2c_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (data[1] == SMP_PHY_CONTROL &&
|
||||
(data[10] == SMP_PHY_CONTROL_LINK_RESET ||
|
||||
data[10] == SMP_PHY_CONTROL_HARD_RESET))
|
||||
adapter->reset_desc.adapter_link_resetting = 1;
|
||||
|
||||
leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr,
|
||||
h2c_size, c2h_dma_addr, c2h_size);
|
||||
leapraid_fire_task(adapter, taskid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void leapraid_ctl_sas_io_unit_ctrl_cmd(struct leapraid_adapter *adapter,
|
||||
void *ctl_sp_req,
|
||||
dma_addr_t h2c_dma_addr,
|
||||
size_t h2c_size,
|
||||
dma_addr_t c2h_dma_addr,
|
||||
size_t c2h_size,
|
||||
void *psge, u16 taskid)
|
||||
{
|
||||
struct leapraid_sas_io_unit_ctrl_req *sas_io_unit_ctl_req = ctl_sp_req;
|
||||
|
||||
if (sas_io_unit_ctl_req->op == LEAPRAID_SAS_OP_PHY_HARD_RESET ||
|
||||
sas_io_unit_ctl_req->op == LEAPRAID_SAS_OP_PHY_LINK_RESET)
|
||||
adapter->reset_desc.adapter_link_resetting = 1;
|
||||
leapraid_build_mpi_sg(adapter, psge, h2c_dma_addr,
|
||||
h2c_size, c2h_dma_addr, c2h_size);
|
||||
leapraid_fire_task(adapter, taskid);
|
||||
}
|
||||
|
||||
static int leapraid_ctl_do_command(struct leapraid_adapter *adapter,
|
||||
struct leapraid_ioctl_command *karg,
|
||||
void __user *mf)
|
||||
{
|
||||
struct leapraid_req *leap_mpi_req;
|
||||
struct leapraid_req *ctl_sp_mpi_req;
|
||||
u16 taskid;
|
||||
void *h2c = NULL;
|
||||
size_t h2c_size = 0;
|
||||
dma_addr_t h2c_dma_addr = 0;
|
||||
void *c2h = NULL;
|
||||
size_t c2h_size = 0;
|
||||
dma_addr_t c2h_dma_addr = 0;
|
||||
void *psge;
|
||||
unsigned long timeout;
|
||||
u16 dev_hdl = LEAPRAID_INVALID_DEV_HANDLE;
|
||||
bool issue_reset = false;
|
||||
u32 data_sge_offset_bytes;
|
||||
u32 sz;
|
||||
int rc;
|
||||
|
||||
rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_SHORT,
|
||||
__func__);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
leap_mpi_req = kzalloc(LEAPRAID_REQUEST_SIZE, GFP_KERNEL);
|
||||
if (!leap_mpi_req)
|
||||
return -ENOMEM;
|
||||
|
||||
if (karg->data_sge_offset > (UINT_MAX / LEAPRAID_SGE_OFFSET_SIZE)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Invalid data_sge_offset=%u\n",
|
||||
__func__, karg->data_sge_offset);
|
||||
rc = -EINVAL;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
data_sge_offset_bytes = karg->data_sge_offset *
|
||||
LEAPRAID_SGE_OFFSET_SIZE;
|
||||
if (data_sge_offset_bytes > LEAPRAID_REQUEST_SIZE) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Invalid data_sge_offset=%u\n",
|
||||
__func__, karg->data_sge_offset);
|
||||
rc = -EINVAL;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
if (copy_from_user(leap_mpi_req, mf, data_sge_offset_bytes)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Failed to copy request message from user\n",
|
||||
__func__);
|
||||
rc = -EFAULT;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
h2c_size = karg->h2c_size;
|
||||
c2h_size = karg->c2h_size;
|
||||
rc = leapraid_ctl_validate_sge_offset(adapter, leap_mpi_req,
|
||||
data_sge_offset_bytes,
|
||||
h2c_size, c2h_size);
|
||||
if (rc)
|
||||
goto out_cleanup;
|
||||
|
||||
taskid = adapter->driver_cmds.ctl_cmd.taskid;
|
||||
|
||||
adapter->driver_cmds.ctl_cmd.status = LEAPRAID_CMD_PENDING;
|
||||
memset(&adapter->driver_cmds.ctl_cmd.reply, 0, LEAPRAID_REPLY_SIZE);
|
||||
ctl_sp_mpi_req = leapraid_get_task_desc(adapter, taskid);
|
||||
memset(ctl_sp_mpi_req, 0, LEAPRAID_REQUEST_SIZE);
|
||||
memcpy(ctl_sp_mpi_req, leap_mpi_req, data_sge_offset_bytes);
|
||||
|
||||
if (ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO ||
|
||||
ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH ||
|
||||
ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH) {
|
||||
dev_hdl = le16_to_cpu(ctl_sp_mpi_req->func_dep1);
|
||||
if (!dev_hdl ||
|
||||
dev_hdl > adapter->adapter_attr.features.max_dev_handle) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Invalid device handle\n", __func__);
|
||||
rc = -EINVAL;
|
||||
goto out_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (WARN_ON(ctl_sp_mpi_req->func == LEAPRAID_FUNC_SCSI_TMF)) {
|
||||
rc = -EINVAL;
|
||||
goto out_cleanup;
|
||||
}
|
||||
|
||||
if (h2c_size) {
|
||||
h2c = dma_alloc_coherent(&adapter->pdev->dev, h2c_size,
|
||||
&h2c_dma_addr, GFP_KERNEL);
|
||||
if (!h2c) {
|
||||
rc = -ENOMEM;
|
||||
goto out_cleanup;
|
||||
}
|
||||
if (copy_from_user(h2c, karg->h2c_buf_ptr, h2c_size)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Failed to copy h2c from user\n",
|
||||
__func__);
|
||||
rc = -EFAULT;
|
||||
goto out_cleanup;
|
||||
}
|
||||
}
|
||||
if (c2h_size) {
|
||||
c2h = dma_alloc_coherent(&adapter->pdev->dev, c2h_size,
|
||||
&c2h_dma_addr, GFP_KERNEL);
|
||||
if (!c2h) {
|
||||
rc = -ENOMEM;
|
||||
goto out_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
psge = (void *)ctl_sp_mpi_req + data_sge_offset_bytes;
|
||||
init_completion(&adapter->driver_cmds.ctl_cmd.done);
|
||||
|
||||
switch (ctl_sp_mpi_req->func) {
|
||||
case LEAPRAID_FUNC_SCSIIO:
|
||||
case LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH:
|
||||
leapraid_ctl_scsiio_cmd(adapter, ctl_sp_mpi_req, taskid,
|
||||
h2c_dma_addr, h2c_size,
|
||||
c2h_dma_addr, c2h_size,
|
||||
dev_hdl, psge);
|
||||
break;
|
||||
case LEAPRAID_FUNC_SMP_PASSTHROUGH:
|
||||
if (!h2c) {
|
||||
rc = -EINVAL;
|
||||
goto out_cleanup;
|
||||
}
|
||||
rc = leapraid_ctl_smp_passthrough_cmd(adapter,
|
||||
ctl_sp_mpi_req, taskid,
|
||||
h2c_dma_addr, h2c_size,
|
||||
c2h_dma_addr, c2h_size,
|
||||
psge, h2c);
|
||||
if (rc)
|
||||
goto out_cleanup;
|
||||
break;
|
||||
case LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH:
|
||||
leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, h2c_size,
|
||||
c2h_dma_addr, c2h_size);
|
||||
leapraid_fire_task(adapter, taskid);
|
||||
break;
|
||||
case LEAPRAID_FUNC_FW_DOWNLOAD:
|
||||
case LEAPRAID_FUNC_FW_UPLOAD:
|
||||
leapraid_build_ieee_sg(adapter, psge, h2c_dma_addr, h2c_size,
|
||||
c2h_dma_addr, c2h_size);
|
||||
leapraid_fire_task(adapter, taskid);
|
||||
break;
|
||||
case LEAPRAID_FUNC_SAS_IO_UNIT_CTRL:
|
||||
leapraid_ctl_sas_io_unit_ctrl_cmd(adapter, ctl_sp_mpi_req,
|
||||
h2c_dma_addr, h2c_size,
|
||||
c2h_dma_addr, c2h_size,
|
||||
psge, taskid);
|
||||
break;
|
||||
default:
|
||||
leapraid_build_mpi_sg(adapter, psge, h2c_dma_addr,
|
||||
h2c_size, c2h_dma_addr, c2h_size);
|
||||
leapraid_fire_task(adapter, taskid);
|
||||
break;
|
||||
}
|
||||
|
||||
timeout = karg->timeout;
|
||||
if (timeout < LEAPRAID_CTL_CMD_TIMEOUT)
|
||||
timeout = LEAPRAID_CTL_CMD_TIMEOUT;
|
||||
if (!wait_for_completion_timeout(&adapter->driver_cmds.ctl_cmd.done,
|
||||
timeout * HZ)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: ctl_cmd timeout, status=0x%x\n",
|
||||
__func__, adapter->driver_cmds.ctl_cmd.status);
|
||||
leapraid_log_req_context(adapter, taskid, ctl_sp_mpi_req);
|
||||
}
|
||||
|
||||
if ((leap_mpi_req->func == LEAPRAID_FUNC_SMP_PASSTHROUGH ||
|
||||
leap_mpi_req->func == LEAPRAID_FUNC_SAS_IO_UNIT_CTRL) &&
|
||||
adapter->reset_desc.adapter_link_resetting)
|
||||
adapter->reset_desc.adapter_link_resetting = 0;
|
||||
|
||||
if (!(adapter->driver_cmds.ctl_cmd.status & LEAPRAID_CMD_DONE)) {
|
||||
issue_reset =
|
||||
leapraid_check_reset(
|
||||
adapter->driver_cmds.ctl_cmd.status);
|
||||
goto reset;
|
||||
}
|
||||
|
||||
if (c2h_size && copy_to_user(karg->c2h_buf_ptr, c2h, c2h_size)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Failed to copy c2h to user\n", __func__);
|
||||
rc = -ENODATA;
|
||||
goto out_cleanup;
|
||||
}
|
||||
if (karg->max_rep_bytes) {
|
||||
sz = min_t(u32, karg->max_rep_bytes, LEAPRAID_REPLY_SIZE);
|
||||
if (copy_to_user(karg->rep_msg_buf_ptr,
|
||||
&adapter->driver_cmds.ctl_cmd.reply,
|
||||
sz)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Failed to copy reply to user\n",
|
||||
__func__);
|
||||
rc = -ENODATA;
|
||||
goto out_cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (karg->max_sense_bytes &&
|
||||
(leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO ||
|
||||
leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH)) {
|
||||
if (!karg->sense_data_ptr)
|
||||
goto out_cleanup;
|
||||
|
||||
sz = min_t(u32, karg->max_sense_bytes, SCSI_SENSE_BUFFERSIZE);
|
||||
if (copy_to_user(karg->sense_data_ptr,
|
||||
&adapter->driver_cmds.ctl_cmd.sense,
|
||||
sz)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Failed to copy sense data to user\n",
|
||||
__func__);
|
||||
rc = -ENODATA;
|
||||
goto out_cleanup;
|
||||
}
|
||||
}
|
||||
reset:
|
||||
if (issue_reset) {
|
||||
rc = -ENODATA;
|
||||
if (leap_mpi_req->func == LEAPRAID_FUNC_SCSIIO ||
|
||||
leap_mpi_req->func ==
|
||||
LEAPRAID_FUNC_SCSIIO_RAID_PASSTHROUGH ||
|
||||
leap_mpi_req->func ==
|
||||
LEAPRAID_FUNC_SCSIIO_SATA_PASSTHROUGH) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"Fire tgt reset, hdl=0x%04x\n",
|
||||
le16_to_cpu(leap_mpi_req->func_dep1));
|
||||
leapraid_issue_locked_tm(
|
||||
adapter,
|
||||
le16_to_cpu(leap_mpi_req->func_dep1), 0, 0, 0,
|
||||
LEAPRAID_TM_TASKTYPE_TARGET_RESET, taskid,
|
||||
LEAPRAID_TM_MSGFLAGS_LINK_RESET);
|
||||
} else {
|
||||
dev_info(&adapter->pdev->dev,
|
||||
"%s:%d: call hard_reset\n",
|
||||
__func__, __LINE__);
|
||||
leapraid_hard_reset_handler(adapter, FULL_RESET);
|
||||
}
|
||||
}
|
||||
out_cleanup:
|
||||
if (c2h)
|
||||
dma_free_coherent(&adapter->pdev->dev, c2h_size,
|
||||
c2h, c2h_dma_addr);
|
||||
if (h2c)
|
||||
dma_free_coherent(&adapter->pdev->dev, h2c_size,
|
||||
h2c, h2c_dma_addr);
|
||||
kfree(leap_mpi_req);
|
||||
adapter->driver_cmds.ctl_cmd.status = LEAPRAID_CMD_NOT_USED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int leapraid_ctl_get_adapter_info(struct leapraid_adapter *adapter,
|
||||
void __user *arg)
|
||||
{
|
||||
struct leapraid_ioctl_adapter_info *karg;
|
||||
u8 revision;
|
||||
int rc = 0;
|
||||
|
||||
karg = kzalloc_obj(*karg);
|
||||
if (!karg)
|
||||
return -ENOMEM;
|
||||
|
||||
pci_read_config_byte(adapter->pdev, PCI_CLASS_REVISION, &revision);
|
||||
karg->revision = revision;
|
||||
karg->pci_id = adapter->pdev->device;
|
||||
karg->sub_dev = adapter->pdev->subsystem_device;
|
||||
karg->sub_vendor = adapter->pdev->subsystem_vendor;
|
||||
karg->pci_info.u.bits.bus = adapter->pdev->bus->number;
|
||||
karg->pci_info.u.bits.dev = PCI_SLOT(adapter->pdev->devfn);
|
||||
karg->pci_info.u.bits.func = PCI_FUNC(adapter->pdev->devfn);
|
||||
karg->pci_info.seg_id = pci_domain_nr(adapter->pdev->bus);
|
||||
karg->fw_ver = adapter->adapter_attr.features.fw_version;
|
||||
|
||||
snprintf(karg->driver_ver, sizeof(karg->driver_ver), "%s-%s",
|
||||
LEAPRAID_DRIVER_NAME, LEAPRAID_DRIVER_VERSION);
|
||||
|
||||
karg->adapter_type = LEAPRAID_IOCTL_VERSION;
|
||||
karg->bios_ver = adapter->adapter_attr.bios_version;
|
||||
if (copy_to_user(arg, karg,
|
||||
sizeof(struct leapraid_ioctl_adapter_info))) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Failed to copy info to user\n", __func__);
|
||||
rc = -EFAULT;
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
free_buf:
|
||||
kfree(karg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int leapraid_ctl_ioctl_main(struct file *file, unsigned int cmd,
|
||||
void __user *arg)
|
||||
{
|
||||
struct leapraid_ioctl_header ioctl_header;
|
||||
struct leapraid_adapter *adapter = NULL;
|
||||
struct leapraid_ioctl_command __user *uarg;
|
||||
struct leapraid_ioctl_command karg;
|
||||
int rc = -ENOIOCTLCMD;
|
||||
|
||||
if (copy_from_user(&ioctl_header, arg,
|
||||
sizeof(struct leapraid_ioctl_header))) {
|
||||
pr_err("%s:%s: Failed to copy header from user\n",
|
||||
LEAPRAID_DRIVER_NAME, __func__);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
adapter = leapraid_ctl_lookup_adapter(ioctl_header.adapter_id);
|
||||
if (!adapter)
|
||||
return -EFAULT;
|
||||
|
||||
if (atomic_read(&adapter->overheat_desc.thermal_alert)) {
|
||||
dev_warn(&adapter->pdev->dev,
|
||||
"%s: Failed, thermal_alert=%d\n",
|
||||
__func__,
|
||||
atomic_read(&adapter->overheat_desc.thermal_alert));
|
||||
rc = -EFAULT;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
mutex_lock(&adapter->access_ctrl.pci_access_lock);
|
||||
|
||||
rc = leapraid_check_adapter_is_op(adapter, LEAPRAID_DB_WAIT_OP_LONG,
|
||||
__func__);
|
||||
if (rc)
|
||||
goto unlock;
|
||||
|
||||
if (!wait_event_timeout(adapter->access_ctrl.shost_recover_wq,
|
||||
!adapter->access_ctrl.shost_recover_async,
|
||||
LEAPRAID_WAIT_SHOST_RECOVERY * HZ)) {
|
||||
dev_warn(&adapter->pdev->dev,
|
||||
"Timeout waiting for shost recovery async\n");
|
||||
rc = -EAGAIN;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (adapter->access_ctrl.pcie_recovering ||
|
||||
adapter->scan_dev_desc.driver_loading ||
|
||||
adapter->access_ctrl.host_removing) {
|
||||
rc = -EAGAIN;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
if (!mutex_trylock(&adapter->driver_cmds.ctl_cmd.mutex)) {
|
||||
rc = -EAGAIN;
|
||||
goto unlock;
|
||||
}
|
||||
} else if (mutex_lock_interruptible(&adapter->driver_cmds
|
||||
.ctl_cmd.mutex)) {
|
||||
rc = -ERESTARTSYS;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
switch (_IOC_NR(cmd)) {
|
||||
case LEAPRAID_ADAPTER_INFO:
|
||||
if (_IOC_SIZE(cmd) ==
|
||||
sizeof(struct leapraid_ioctl_adapter_info))
|
||||
rc = leapraid_ctl_get_adapter_info(adapter, arg);
|
||||
break;
|
||||
case LEAPRAID_COMMAND:
|
||||
if (copy_from_user(&karg, arg, sizeof(karg))) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"%s: Failed to copy data from user\n",
|
||||
__func__);
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
if (karg.hdr.adapter_id != ioctl_header.adapter_id) {
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_IOC_SIZE(cmd) == sizeof(struct leapraid_ioctl_command)) {
|
||||
uarg = arg;
|
||||
rc = leapraid_ctl_do_command(adapter, &karg,
|
||||
&uarg->mf);
|
||||
if (rc)
|
||||
dev_warn(&adapter->pdev->dev,
|
||||
"%s: IOCTL cmd failed rc=%d\n",
|
||||
__func__, rc);
|
||||
}
|
||||
break;
|
||||
case LEAPRAID_EVENTQUERY:
|
||||
case LEAPRAID_EVENTREPORT:
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"Unknown IOCTL opcode=0x%08x\n", cmd);
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&adapter->driver_cmds.ctl_cmd.mutex);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&adapter->access_ctrl.pci_access_lock);
|
||||
out_put:
|
||||
leapraid_ctl_put_adapter(adapter);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static long leapraid_ctl_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
return leapraid_ctl_ioctl_main(file, cmd, (void __user *)arg);
|
||||
}
|
||||
|
||||
static void leapraid_fw_mmap_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct leapraid_adapter *adapter = vma->vm_private_data;
|
||||
|
||||
if (!adapter)
|
||||
return;
|
||||
|
||||
atomic_inc(&adapter->fw_log_desc.mmap_refcnt);
|
||||
}
|
||||
|
||||
static void leapraid_fw_mmap_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct leapraid_adapter *adapter = vma->vm_private_data;
|
||||
|
||||
if (!adapter)
|
||||
return;
|
||||
|
||||
if (atomic_dec_and_test(&adapter->fw_log_desc.mmap_refcnt))
|
||||
wake_up(&adapter->fw_log_desc.mmap_waitq);
|
||||
leapraid_ctl_put_adapter(adapter);
|
||||
}
|
||||
|
||||
static const struct vm_operations_struct leapraid_fw_mmap_vm_ops = {
|
||||
.open = leapraid_fw_mmap_open,
|
||||
.close = leapraid_fw_mmap_close,
|
||||
};
|
||||
|
||||
static int leapraid_fw_mmap(struct file *filp, struct vm_area_struct *vma)
|
||||
{
|
||||
struct leapraid_adapter *adapter = NULL;
|
||||
/* Userspace passes the adapter ID via vma->vm_pgoff. */
|
||||
u32 adapter_id = vma->vm_pgoff;
|
||||
unsigned long length;
|
||||
int rc = -EINVAL;
|
||||
|
||||
length = vma->vm_end - vma->vm_start;
|
||||
|
||||
adapter = leapraid_ctl_lookup_adapter(adapter_id);
|
||||
if (!adapter) {
|
||||
pr_err("%s: No adapter found!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (READ_ONCE(adapter->access_ctrl.host_removing)) {
|
||||
rc = -EAGAIN;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
if (length > (LEAPRAID_SYS_LOG_BUF_SIZE +
|
||||
LEAPRAID_SYS_LOG_BUF_RESERVE)) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"Requested mapping size is too large!\n");
|
||||
rc = -EINVAL;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
if (!adapter->fw_log_desc.fw_log_buffer) {
|
||||
dev_err(&adapter->pdev->dev, "No log buffer!\n");
|
||||
rc = -EINVAL;
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
vma->vm_pgoff = 0;
|
||||
|
||||
rc = dma_mmap_coherent(&adapter->pdev->dev, vma,
|
||||
adapter->fw_log_desc.fw_log_buffer,
|
||||
adapter->fw_log_desc.fw_log_buffer_dma,
|
||||
length);
|
||||
if (rc) {
|
||||
dev_err(&adapter->pdev->dev,
|
||||
"Failed to map memory to user space!\n");
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
vma->vm_private_data = adapter;
|
||||
vma->vm_ops = &leapraid_fw_mmap_vm_ops;
|
||||
leapraid_fw_mmap_open(vma);
|
||||
adapter = NULL;
|
||||
|
||||
rc = 0;
|
||||
out_put:
|
||||
leapraid_ctl_put_adapter(adapter);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct file_operations leapraid_ctl_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = leapraid_ctl_ioctl,
|
||||
.mmap = leapraid_fw_mmap,
|
||||
};
|
||||
|
||||
static struct miscdevice leapraid_ctl_dev = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = LEAPRAID_DEV_NAME,
|
||||
.fops = &leapraid_ctl_fops,
|
||||
};
|
||||
|
||||
int leapraid_ctl_init(void)
|
||||
{
|
||||
if (misc_register(&leapraid_ctl_dev) < 0) {
|
||||
pr_err("%s Can't register misc device\n",
|
||||
LEAPRAID_DRIVER_NAME);
|
||||
return -ENODEV;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void leapraid_ctl_exit(void)
|
||||
{
|
||||
misc_deregister(&leapraid_ctl_dev);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -9,3 +9,5 @@ mpt3sas-y += mpt3sas_base.o \
|
||||
mpt3sas_trigger_diag.o \
|
||||
mpt3sas_warpdrive.o \
|
||||
mpt3sas_debugfs.o \
|
||||
|
||||
mpt3sas-$(CONFIG_HWMON) += mpt3sas_hwmon.o
|
||||
|
||||
@@ -8369,11 +8369,7 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc)
|
||||
return r; /* scan_start and scan_finished support */
|
||||
}
|
||||
|
||||
r = _base_send_port_enable(ioc);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
return r;
|
||||
return _base_send_port_enable(ioc);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1629,6 +1629,9 @@ struct MPT3SAS_ADAPTER {
|
||||
u8 is_aero_ioc;
|
||||
struct dentry *debugfs_root;
|
||||
struct dentry *ioc_dump;
|
||||
#if IS_REACHABLE(CONFIG_HWMON)
|
||||
struct mpt3sas_hwmon *hwmon;
|
||||
#endif
|
||||
PUT_SMID_IO_FP_HIP put_smid_scsi_io;
|
||||
PUT_SMID_IO_FP_HIP put_smid_fast_path;
|
||||
PUT_SMID_IO_FP_HIP put_smid_hi_priority;
|
||||
@@ -1904,6 +1907,9 @@ int mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc,
|
||||
Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);
|
||||
int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
|
||||
int mpt3sas_config_get_iounit_pg7(struct MPT3SAS_ADAPTER *ioc,
|
||||
Mpi2ConfigReply_t *mpi_reply,
|
||||
Mpi2IOUnitPage7_t *config_page);
|
||||
int mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
|
||||
*mpi_reply, Mpi2IOUnitPage8_t *config_page);
|
||||
int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
|
||||
@@ -2047,6 +2053,20 @@ void mpt3sas_destroy_debugfs(struct MPT3SAS_ADAPTER *ioc);
|
||||
void mpt3sas_init_debugfs(void);
|
||||
void mpt3sas_exit_debugfs(void);
|
||||
|
||||
#if IS_REACHABLE(CONFIG_HWMON)
|
||||
int mpt3sas_hwmon_register(struct MPT3SAS_ADAPTER *ioc);
|
||||
void mpt3sas_hwmon_unregister(struct MPT3SAS_ADAPTER *ioc);
|
||||
#else
|
||||
static inline int mpt3sas_hwmon_register(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mpt3sas_hwmon_unregister(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* _scsih_is_pcie_scsi_device - determines if device is an pcie scsi device
|
||||
* @device_info: bitfield providing information about the device.
|
||||
|
||||
@@ -991,6 +991,42 @@ mpt3sas_config_get_iounit_pg3(struct MPT3SAS_ADAPTER *ioc,
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_config_get_iounit_pg7 - obtain iounit page 7
|
||||
* @ioc: per adapter object
|
||||
* @mpi_reply: reply mf payload returned from firmware
|
||||
* @config_page: contents of the config page
|
||||
* Context: sleep.
|
||||
*
|
||||
* Return: 0 for success, non-zero for failure.
|
||||
*/
|
||||
int mpt3sas_config_get_iounit_pg7(struct MPT3SAS_ADAPTER *ioc,
|
||||
Mpi2ConfigReply_t *mpi_reply,
|
||||
Mpi2IOUnitPage7_t *config_page)
|
||||
{
|
||||
Mpi2ConfigRequest_t mpi_request;
|
||||
int r;
|
||||
|
||||
memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
|
||||
mpi_request.Function = MPI2_FUNCTION_CONFIG;
|
||||
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
|
||||
mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
|
||||
mpi_request.Header.PageNumber = 7;
|
||||
mpi_request.Header.PageVersion = MPI2_IOUNITPAGE7_PAGEVERSION;
|
||||
ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
|
||||
r = _config_request(ioc, &mpi_request, mpi_reply,
|
||||
MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
|
||||
if (r)
|
||||
goto out;
|
||||
|
||||
mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
|
||||
r = _config_request(ioc, &mpi_request, mpi_reply,
|
||||
MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT,
|
||||
config_page, sizeof(*config_page));
|
||||
out:
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_config_get_iounit_pg8 - obtain iounit page 8
|
||||
* @ioc: per adapter object
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Hardware monitoring (hwmon) support for the LSI / Broadcom mpt3sas
|
||||
* SAS HBA driver. Exposes the IOC and board temperature sensors by
|
||||
* reading MPI IO Unit Page 7.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "mpt3sas_base.h"
|
||||
|
||||
struct mpt3sas_hwmon {
|
||||
struct MPT3SAS_ADAPTER *ioc;
|
||||
struct device *hwmon_dev;
|
||||
bool ioc_present;
|
||||
bool board_present;
|
||||
};
|
||||
|
||||
/*
|
||||
* Convert a (raw, units) reading to millidegrees Celsius.
|
||||
* Returns -ENODATA when the sensor reports "not present" or
|
||||
* unknown units. Temperature values are interpreted as signed
|
||||
* two's-complement integers.
|
||||
*
|
||||
* The MPI2_IOUNITPAGE7_IOC_TEMP_* and MPI2_IOUNITPAGE7_BOARD_TEMP_*
|
||||
* defines in mpi2_cnfg.h share the same values; the IOC ones are
|
||||
* used for both channels.
|
||||
*/
|
||||
static int _hwmon_to_mdegc(s16 raw, u8 units, long *out)
|
||||
{
|
||||
switch (units) {
|
||||
case MPI2_IOUNITPAGE7_IOC_TEMP_CELSIUS:
|
||||
*out = (long)raw * 1000;
|
||||
return 0;
|
||||
case MPI2_IOUNITPAGE7_IOC_TEMP_FAHRENHEIT:
|
||||
/* (F - 32) * 5 / 9, expressed in milli-units */
|
||||
*out = ((long)raw - 32) * 5000 / 9;
|
||||
return 0;
|
||||
default:
|
||||
return -ENODATA;
|
||||
}
|
||||
}
|
||||
|
||||
static umode_t _hwmon_is_visible(const void *drvdata,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel)
|
||||
{
|
||||
const struct mpt3sas_hwmon *h = drvdata;
|
||||
|
||||
if (type != hwmon_temp)
|
||||
return 0;
|
||||
if (attr != hwmon_temp_input && attr != hwmon_temp_label)
|
||||
return 0;
|
||||
if (channel == 0 && h->ioc_present)
|
||||
return 0444;
|
||||
if (channel == 1 && h->board_present)
|
||||
return 0444;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
struct mpt3sas_hwmon *h = dev_get_drvdata(dev);
|
||||
Mpi2ConfigReply_t mpi_reply;
|
||||
Mpi2IOUnitPage7_t page;
|
||||
int r;
|
||||
|
||||
if (type != hwmon_temp || attr != hwmon_temp_input)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
r = mpt3sas_config_get_iounit_pg7(h->ioc, &mpi_reply, &page);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
if (channel == 0)
|
||||
return _hwmon_to_mdegc((s16)le16_to_cpu(page.IOCTemperature),
|
||||
page.IOCTemperatureUnits, val);
|
||||
if (channel == 1)
|
||||
return _hwmon_to_mdegc((s16)le16_to_cpu(page.BoardTemperature),
|
||||
page.BoardTemperatureUnits, val);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static const char * const mpt3sas_hwmon_temp_labels[] = {
|
||||
"IOC",
|
||||
"Board",
|
||||
};
|
||||
|
||||
static int _hwmon_read_string(struct device *dev,
|
||||
enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, const char **str)
|
||||
{
|
||||
if (type != hwmon_temp || attr != hwmon_temp_label)
|
||||
return -EOPNOTSUPP;
|
||||
*str = mpt3sas_hwmon_temp_labels[channel];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hwmon_channel_info * const mpt3sas_hwmon_info[] = {
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL,
|
||||
HWMON_T_INPUT | HWMON_T_LABEL),
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct hwmon_ops mpt3sas_hwmon_ops = {
|
||||
.is_visible = _hwmon_is_visible,
|
||||
.read = _hwmon_read,
|
||||
.read_string = _hwmon_read_string,
|
||||
};
|
||||
|
||||
static const struct hwmon_chip_info mpt3sas_hwmon_chip_info = {
|
||||
.ops = &mpt3sas_hwmon_ops,
|
||||
.info = mpt3sas_hwmon_info,
|
||||
};
|
||||
|
||||
/**
|
||||
* mpt3sas_hwmon_register - register an hwmon device for the IOC
|
||||
* @ioc: per adapter object
|
||||
* Context: sleep.
|
||||
*
|
||||
* Succeeds without registering when no temperature sensors are present,
|
||||
* so cards without thermal monitoring do not expose an empty hwmon node.
|
||||
* Paired with mpt3sas_hwmon_unregister() from the driver's remove path.
|
||||
*
|
||||
* Return: 0 for success, non-zero for failure.
|
||||
*/
|
||||
int mpt3sas_hwmon_register(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
struct device *parent = &ioc->pdev->dev;
|
||||
struct mpt3sas_hwmon *h;
|
||||
struct device *hwdev;
|
||||
Mpi2ConfigReply_t mpi_reply;
|
||||
Mpi2IOUnitPage7_t page;
|
||||
int r;
|
||||
|
||||
r = mpt3sas_config_get_iounit_pg7(ioc, &mpi_reply, &page);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/*
|
||||
* A page where both *TemperatureUnits are NOT_PRESENT covers
|
||||
* two cases: cards that genuinely lack sensors, and firmware
|
||||
* errors that left the page zero-filled (the accessor mirrors
|
||||
* _config_request() behaviour). Either way: skip registration.
|
||||
*/
|
||||
if (page.IOCTemperatureUnits == MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT &&
|
||||
page.BoardTemperatureUnits == MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT)
|
||||
return 0;
|
||||
|
||||
h = kzalloc_obj(*h);
|
||||
if (!h)
|
||||
return -ENOMEM;
|
||||
|
||||
h->ioc = ioc;
|
||||
h->ioc_present = page.IOCTemperatureUnits != MPI2_IOUNITPAGE7_IOC_TEMP_NOT_PRESENT;
|
||||
h->board_present = page.BoardTemperatureUnits != MPI2_IOUNITPAGE7_BOARD_TEMP_NOT_PRESENT;
|
||||
|
||||
hwdev = hwmon_device_register_with_info(parent, "mpt3sas", h,
|
||||
&mpt3sas_hwmon_chip_info,
|
||||
NULL);
|
||||
if (IS_ERR(hwdev)) {
|
||||
kfree(h);
|
||||
return PTR_ERR(hwdev);
|
||||
}
|
||||
|
||||
h->hwmon_dev = hwdev;
|
||||
ioc->hwmon = h;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mpt3sas_hwmon_unregister - tear down the hwmon device, if any
|
||||
* @ioc: per adapter object
|
||||
*
|
||||
* Safe to call when registration was skipped (no sensors) or
|
||||
* failed; in those cases ioc->hwmon is NULL and this is a no-op.
|
||||
*/
|
||||
void mpt3sas_hwmon_unregister(struct MPT3SAS_ADAPTER *ioc)
|
||||
{
|
||||
struct mpt3sas_hwmon *h = ioc->hwmon;
|
||||
|
||||
if (!h)
|
||||
return;
|
||||
hwmon_device_unregister(h->hwmon_dev);
|
||||
kfree(h);
|
||||
ioc->hwmon = NULL;
|
||||
}
|
||||
@@ -12562,6 +12562,7 @@ static void scsih_remove(struct pci_dev *pdev)
|
||||
/* release all the volumes */
|
||||
_scsih_ir_shutdown(ioc);
|
||||
mpt3sas_destroy_debugfs(ioc);
|
||||
mpt3sas_hwmon_unregister(ioc);
|
||||
sas_remove_host(shost);
|
||||
list_for_each_entry_safe(raid_device, next, &ioc->raid_device_list,
|
||||
list) {
|
||||
@@ -13651,6 +13652,11 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
}
|
||||
|
||||
scsi_scan_host(shost);
|
||||
|
||||
if (mpt3sas_hwmon_register(ioc))
|
||||
ioc_warn(ioc,
|
||||
"hwmon registration failed; temperatures not exposed\n");
|
||||
|
||||
mpt3sas_setup_debugfs(ioc);
|
||||
return 0;
|
||||
out_add_shost_fail:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -816,7 +815,9 @@ qla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
|
||||
"Unable to allocate memory for VPD information update.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
ha->isp_ops->get_flash_version(vha, tmp_data);
|
||||
mutex_unlock(&ha->optrom_mutex);
|
||||
vfree(tmp_data);
|
||||
break;
|
||||
}
|
||||
@@ -1472,6 +1473,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 +1504,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 +1528,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 +1544,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 +1573,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 +1584,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 +1600,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");
|
||||
@@ -1660,10 +1678,8 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
|
||||
rval = qla2x00_get_firmware_state(vha, state);
|
||||
mutex_unlock(&vha->hw->optrom_mutex);
|
||||
out:
|
||||
if (rval != QLA_SUCCESS) {
|
||||
if (rval != QLA_SUCCESS)
|
||||
memset(state, -1, sizeof(state));
|
||||
rval = qla2x00_get_firmware_state(vha, state);
|
||||
}
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
|
||||
state[0], state[1], state[2], state[3], state[4], state[5]);
|
||||
@@ -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)
|
||||
|
||||
+560
-62
@@ -160,6 +160,12 @@ qla24xx_proc_fcp_prio_cfg_cmd(struct bsg_job *bsg_job)
|
||||
goto exit_fcp_prio_cfg;
|
||||
}
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t)) {
|
||||
ret = -EINVAL;
|
||||
goto exit_fcp_prio_cfg;
|
||||
}
|
||||
|
||||
/* Get the sub command */
|
||||
oper = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
|
||||
@@ -758,6 +764,10 @@ qla2x00_process_loopback(struct bsg_job *bsg_job)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + 3 * sizeof(uint32_t))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&elreq, 0, sizeof(elreq));
|
||||
|
||||
elreq.req_sg_cnt = dma_map_sg(&ha->pdev->dev,
|
||||
@@ -990,6 +1000,10 @@ qla84xx_reset(struct bsg_job *bsg_job)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t))
|
||||
return -EINVAL;
|
||||
|
||||
flag = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
|
||||
rval = qla84xx_reset_chip(vha, flag == A84_ISSUE_RESET_DIAG_FW);
|
||||
@@ -1034,6 +1048,10 @@ qla84xx_updatefw(struct bsg_job *bsg_job)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t))
|
||||
return -EINVAL;
|
||||
|
||||
sg_cnt = dma_map_sg(&ha->pdev->dev, bsg_job->request_payload.sg_list,
|
||||
bsg_job->request_payload.sg_cnt, DMA_TO_DEVICE);
|
||||
if (!sg_cnt) {
|
||||
@@ -1407,23 +1425,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 +1440,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 +1524,31 @@ 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;
|
||||
int rval = 0;
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t))
|
||||
return -EINVAL;
|
||||
|
||||
start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
|
||||
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 +1575,22 @@ 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;
|
||||
int rval = 0;
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t))
|
||||
return -EINVAL;
|
||||
|
||||
start = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
|
||||
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 +1622,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)
|
||||
{
|
||||
@@ -1562,12 +2003,12 @@ qla2x00_update_fru_versions(struct bsg_job *bsg_job)
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int rval = 0;
|
||||
uint8_t bsg[DMA_POOL_SIZE];
|
||||
uint8_t bsg[DMA_POOL_SIZE] = {};
|
||||
struct qla_image_version_list *list = (void *)bsg;
|
||||
struct qla_image_version *image;
|
||||
uint32_t count;
|
||||
dma_addr_t sfp_dma;
|
||||
void *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
void *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
|
||||
if (!sfp) {
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
@@ -1580,6 +2021,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,
|
||||
@@ -1615,10 +2063,10 @@ qla2x00_read_fru_status(struct bsg_job *bsg_job)
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int rval = 0;
|
||||
uint8_t bsg[DMA_POOL_SIZE];
|
||||
uint8_t bsg[DMA_POOL_SIZE] = {};
|
||||
struct qla_status_reg *sr = (void *)bsg;
|
||||
dma_addr_t sfp_dma;
|
||||
uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
uint8_t *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
|
||||
if (!sfp) {
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
@@ -1666,10 +2114,10 @@ qla2x00_write_fru_status(struct bsg_job *bsg_job)
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int rval = 0;
|
||||
uint8_t bsg[DMA_POOL_SIZE];
|
||||
uint8_t bsg[DMA_POOL_SIZE] = {};
|
||||
struct qla_status_reg *sr = (void *)bsg;
|
||||
dma_addr_t sfp_dma;
|
||||
uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
uint8_t *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
|
||||
if (!sfp) {
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
@@ -1713,10 +2161,10 @@ qla2x00_write_i2c(struct bsg_job *bsg_job)
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int rval = 0;
|
||||
uint8_t bsg[DMA_POOL_SIZE];
|
||||
uint8_t bsg[DMA_POOL_SIZE] = {};
|
||||
struct qla_i2c_access *i2c = (void *)bsg;
|
||||
dma_addr_t sfp_dma;
|
||||
uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
uint8_t *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
|
||||
if (!sfp) {
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
@@ -1727,6 +2175,12 @@ qla2x00_write_i2c(struct bsg_job *bsg_job)
|
||||
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
|
||||
bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c));
|
||||
|
||||
if (i2c->length > sizeof(i2c->buffer)) {
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_INVALID_PARAM;
|
||||
goto dealloc;
|
||||
}
|
||||
|
||||
memcpy(sfp, i2c->buffer, i2c->length);
|
||||
rval = qla2x00_write_sfp(vha, sfp_dma, sfp,
|
||||
i2c->device, i2c->offset, i2c->length, i2c->option);
|
||||
@@ -1759,10 +2213,10 @@ qla2x00_read_i2c(struct bsg_job *bsg_job)
|
||||
scsi_qla_host_t *vha = shost_priv(host);
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
int rval = 0;
|
||||
uint8_t bsg[DMA_POOL_SIZE];
|
||||
uint8_t bsg[DMA_POOL_SIZE] = {};
|
||||
struct qla_i2c_access *i2c = (void *)bsg;
|
||||
dma_addr_t sfp_dma;
|
||||
uint8_t *sfp = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
uint8_t *sfp = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &sfp_dma);
|
||||
|
||||
if (!sfp) {
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
@@ -1773,6 +2227,12 @@ qla2x00_read_i2c(struct bsg_job *bsg_job)
|
||||
sg_copy_to_buffer(bsg_job->request_payload.sg_list,
|
||||
bsg_job->request_payload.sg_cnt, i2c, sizeof(*i2c));
|
||||
|
||||
if (i2c->length > sizeof(i2c->buffer)) {
|
||||
bsg_reply->reply_data.vendor_reply.vendor_rsp[0] =
|
||||
EXT_STATUS_INVALID_PARAM;
|
||||
goto dealloc;
|
||||
}
|
||||
|
||||
rval = qla2x00_read_sfp(vha, sfp_dma, sfp,
|
||||
i2c->device, i2c->offset, i2c->length, i2c->option);
|
||||
|
||||
@@ -1993,6 +2453,11 @@ qlafx00_mgmt_cmd(struct bsg_job *bsg_job)
|
||||
struct fc_port *fcport;
|
||||
char *type = "FC_BSG_HST_FX_MGMT";
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + sizeof(uint32_t) +
|
||||
sizeof(struct qla_mt_iocb_rqst_fx00))
|
||||
return -EINVAL;
|
||||
|
||||
/* Copy the IOCB specific information */
|
||||
piocb_rqst = (struct qla_mt_iocb_rqst_fx00 *)
|
||||
&bsg_request->rqst_data.h_vendor.vendor_cmd[1];
|
||||
@@ -2195,7 +2660,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 +2693,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 +2741,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 +2857,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 +2983,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 +3025,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,
|
||||
@@ -2906,6 +3379,13 @@ qla2x00_process_vendor_specific(struct scsi_qla_host *vha, struct bsg_job *bsg_j
|
||||
{
|
||||
struct fc_bsg_request *bsg_request = bsg_job->request;
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + sizeof(uint32_t)) {
|
||||
ql_log(ql_log_warn, vha, 0x7000,
|
||||
"BSG request too small for vendor cmd.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_edif, vha, 0x911b, "%s FC_BSG_HST_VENDOR cmd[0]=0x%x\n",
|
||||
__func__, bsg_request->rqst_data.h_vendor.vendor_cmd[0]);
|
||||
|
||||
@@ -3007,6 +3487,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;
|
||||
}
|
||||
@@ -3037,8 +3529,11 @@ qla24xx_bsg_request(struct bsg_job *bsg_job)
|
||||
}
|
||||
|
||||
/* Disable port will bring down the chip, allow enable command */
|
||||
if (bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_MANAGE_HOST_PORT ||
|
||||
bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_GET_HOST_STATS)
|
||||
if (bsg_request->msgcode == FC_BSG_HST_VENDOR &&
|
||||
bsg_job->request_len >=
|
||||
sizeof(struct fc_bsg_request) + sizeof(uint32_t) &&
|
||||
(bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_MANAGE_HOST_PORT ||
|
||||
bsg_request->rqst_data.h_vendor.vendor_cmd[0] == QL_VND_GET_HOST_STATS))
|
||||
goto skip_chip_chk;
|
||||
|
||||
if (vha->hw->flags.port_isolated) {
|
||||
@@ -3347,6 +3842,10 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job)
|
||||
if (!IS_QLA28XX(ha) || vha->vp_idx != 0)
|
||||
return -EPERM;
|
||||
|
||||
if (bsg_job->request_len <
|
||||
sizeof(struct fc_bsg_request) + 2 * sizeof(uint32_t))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ha->optrom_mutex);
|
||||
rval = qla28xx_do_validate_flash_image(bsg_job, &state);
|
||||
if (rval)
|
||||
@@ -3365,9 +3864,8 @@ static int qla28xx_validate_flash_image(struct bsg_job *bsg_job)
|
||||
bsg_reply->result = DID_OK << 16;
|
||||
bsg_reply->reply_payload_rcv_len = 0;
|
||||
bsg_job->reply_len = sizeof(struct fc_bsg_reply);
|
||||
if (!rval)
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
bsg_job_done(bsg_job, bsg_reply->result,
|
||||
bsg_reply->reply_payload_rcv_len);
|
||||
|
||||
return QLA_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -40,6 +40,10 @@
|
||||
#define QL_VND_MBX_PASSTHRU 0x2B
|
||||
#define QL_VND_DPORT_DIAGNOSTICS_V2 0x2C
|
||||
#define QL_VND_IMG_SET_VALID 0x30
|
||||
#define QL_VND_READ_FLASH_BLOCK 0x33
|
||||
#define QL_VND_WRITE_FLASH_BLOCK 0x34
|
||||
#define QL_VND_LOAD_MPI 0x35
|
||||
#define QL_VND_DUMP_MPI 0x36
|
||||
|
||||
/* BSG Vendor specific subcode returns */
|
||||
#define EXT_STATUS_OK 0
|
||||
@@ -83,6 +87,36 @@
|
||||
#define ELS_OPCODE_BYTE 0x10
|
||||
|
||||
/* BSG Vendor specific definations */
|
||||
|
||||
#define QLA_IS_TIM 0x1
|
||||
#define QLA_IS_SECURE 0x2
|
||||
#define QLA_UPDATE_MBR 0x4
|
||||
|
||||
struct qla_block_rw {
|
||||
uint32_t region;
|
||||
uint32_t rw_length;
|
||||
uint32_t options;
|
||||
uint32_t region_offset;
|
||||
uint32_t chunk_length;
|
||||
uint8_t reserved[44];
|
||||
} __packed;
|
||||
|
||||
struct qla_load_dump_mpi {
|
||||
uint32_t mpi_address;
|
||||
uint32_t length;
|
||||
uint32_t options;
|
||||
#define QLA_LDM_SECURE_ENABLE 0x1
|
||||
#define QLA_LDM_OTP_PROV 0x2
|
||||
#define QLA_LDM_DEV_CSR 0x4
|
||||
#define QLA_LDM_AUTH_CMD_BIN 0x8
|
||||
#define QLA_LDM_SHADOW_REGS 0x10
|
||||
#define QLA_LDM_CA_CSR 0x20
|
||||
#define QLA_LDM_MLDSA_ALGO 0x40
|
||||
#define QLA_LDM_MLDSA_SIGNATURE 0x80
|
||||
|
||||
uint8_t reserved[52];
|
||||
} __packed;
|
||||
|
||||
#define A84_ISSUE_WRITE_TYPE_CMD 0
|
||||
#define A84_ISSUE_READ_TYPE_CMD 1
|
||||
#define A84_CLEANUP_CMD 2
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* | | | 0x2127-0x2128 |
|
||||
* | Queue Command and IO tracing | 0x3074 | 0x300b |
|
||||
* | | | 0x3027-0x3028 |
|
||||
* | | | 0x303d-0x3041 |
|
||||
* | | | 0x303e-0x3041 |
|
||||
* | | | 0x302e,0x3033 |
|
||||
* | | | 0x3036,0x3038 |
|
||||
* | | | 0x303a |
|
||||
@@ -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
|
||||
@@ -171,7 +172,7 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram,
|
||||
|
||||
if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
|
||||
/* no interrupt, timed out*/
|
||||
return rval;
|
||||
return QLA_FUNCTION_TIMEOUT;
|
||||
}
|
||||
if (rval) {
|
||||
/* error completion status */
|
||||
@@ -254,7 +255,7 @@ qla24xx_dump_ram(struct qla_hw_data *ha, uint32_t addr, __be32 *ram,
|
||||
|
||||
if (!test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
|
||||
/* no interrupt, timed out*/
|
||||
return rval;
|
||||
return QLA_FUNCTION_TIMEOUT;
|
||||
}
|
||||
if (rval) {
|
||||
/* error completion status */
|
||||
@@ -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;
|
||||
|
||||
+134
-14
@@ -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.
|
||||
@@ -2591,6 +2645,8 @@ typedef struct fc_port {
|
||||
struct list_head list;
|
||||
struct scsi_qla_host *vha;
|
||||
struct list_head unsol_ctx_head;
|
||||
/* Serializes unsol_ctx_head against ISR, DPC and NVMe transport. */
|
||||
spinlock_t unsol_ctx_lock;
|
||||
|
||||
unsigned int conf_compl_supported:1;
|
||||
unsigned int deleted:2;
|
||||
@@ -3503,6 +3559,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 +3591,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 +3799,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 +3834,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;
|
||||
@@ -4100,6 +4178,7 @@ struct qla_hw_data {
|
||||
#define SRB_MIN_REQ 128
|
||||
mempool_t *srb_mempool;
|
||||
u8 port_name[WWN_SIZE];
|
||||
u16 mbregs[32];
|
||||
|
||||
volatile struct {
|
||||
uint32_t mbox_int :1;
|
||||
@@ -4170,7 +4249,10 @@ struct qla_hw_data {
|
||||
uint32_t eeh_flush:2;
|
||||
#define EEH_FLUSH_RDY 1
|
||||
#define EEH_FLUSH_DONE 2
|
||||
uint32_t t262_fail:1;
|
||||
uint32_t t272_fail:1;
|
||||
uint32_t secure_mcu:1;
|
||||
uint32_t valid_flt:1;
|
||||
} flags;
|
||||
|
||||
uint16_t max_exchg;
|
||||
@@ -4256,6 +4338,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 +4370,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 +4403,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 +4444,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 +4458,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 +4470,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 +4489,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 +4507,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 +4552,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 +4584,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 +4810,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 +5006,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 +5021,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 +5440,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 +5589,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 +5712,9 @@ struct ql_vnd_tgt_stats_resp {
|
||||
(!_fcport || IS_SESSION_DELETED(_fcport) || atomic_read(&_fcport->state) != FCS_ONLINE || \
|
||||
!_fcport->vha->hw->flags.fw_started)
|
||||
|
||||
#define is_flash_read(_opt) \
|
||||
(!(_opt & BIT_9) && !(_opt & BIT_6))
|
||||
|
||||
#define is_flash_write(_opt) \
|
||||
(!(_opt & BIT_9) && (_opt & BIT_6))
|
||||
#endif
|
||||
|
||||
@@ -497,7 +497,7 @@ qla2x00_dfs_fce_write(struct file *file, const char __user *buffer,
|
||||
unsigned long enable;
|
||||
|
||||
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha)) {
|
||||
ql_dbg(ql_dbg_user, vha, 0xd034,
|
||||
"this adapter does not support FCE.");
|
||||
return -EINVAL;
|
||||
@@ -510,7 +510,9 @@ qla2x00_dfs_fce_write(struct file *file, const char __user *buffer,
|
||||
return PTR_ERR(buf);
|
||||
}
|
||||
|
||||
enable = kstrtoul(buf, 0, 0);
|
||||
rc = kstrtoul(buf, 0, &enable);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
rc = count;
|
||||
|
||||
mutex_lock(&ha->fce_mutex);
|
||||
@@ -698,7 +700,7 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha)
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
|
||||
if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
|
||||
!IS_QLA27XX(ha) && !IS_QLA28XX(ha) && !IS_QLA29XX(ha))
|
||||
goto out;
|
||||
|
||||
if (qla2x00_dfs_root)
|
||||
|
||||
@@ -2534,7 +2534,7 @@ qla24xx_sa_replace_iocb(srb_t *sp, struct sa_update_28xx *sa_update_iocb)
|
||||
|
||||
void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
|
||||
{
|
||||
struct purex_entry_24xx *p = *pkt;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct enode *ptr;
|
||||
int sid;
|
||||
u16 totlen;
|
||||
@@ -2544,26 +2544,55 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
|
||||
struct fc_port *fcport;
|
||||
struct qla_els_pt_arg a;
|
||||
be_id_t beid;
|
||||
__le16 nport_handle;
|
||||
__le32 rx_xchg_addr;
|
||||
__le16 ox_id;
|
||||
__le16 frame_size, status_flags, trunc_frame_size;
|
||||
uint8_t s_id[3], d_id[3];
|
||||
uint8_t vp_idx;
|
||||
struct purex_entry_24xx *p = *pkt;
|
||||
|
||||
memset(&a, 0, sizeof(a));
|
||||
|
||||
/*
|
||||
* purex_entry_24xx_ext (29xx) overlays purex_entry_24xx for every
|
||||
* field touched here -- nport_handle, rx_xchg_addr, ox_id, frame_size,
|
||||
* status_flags, trunc_frame_size, s_id[3], d_id[3] -- with only
|
||||
* vp_idx differing in width (u8 at offset 6 vs __le16 at offsets 6-7,
|
||||
* with reserved2 at offset 7 in the 24xx layout). So all reads but
|
||||
* vp_idx go through a single struct purex_entry_24xx * view.
|
||||
*/
|
||||
nport_handle = p->nport_handle;
|
||||
rx_xchg_addr = p->rx_xchg_addr;
|
||||
ox_id = p->ox_id;
|
||||
frame_size = p->frame_size;
|
||||
status_flags = p->status_flags;
|
||||
trunc_frame_size = p->trunc_frame_size;
|
||||
memcpy(s_id, p->s_id, sizeof(s_id));
|
||||
memcpy(d_id, p->d_id, sizeof(d_id));
|
||||
if (IS_QLA29XX(ha))
|
||||
vp_idx = le16_to_cpu(((struct purex_entry_24xx_ext *)
|
||||
*pkt)->vp_idx);
|
||||
else
|
||||
vp_idx = p->vp_idx;
|
||||
|
||||
a.els_opcode = ELS_AUTH_ELS;
|
||||
a.nport_handle = p->nport_handle;
|
||||
a.rx_xchg_address = p->rx_xchg_addr;
|
||||
a.did.b.domain = p->s_id[2];
|
||||
a.did.b.area = p->s_id[1];
|
||||
a.did.b.al_pa = p->s_id[0];
|
||||
a.nport_handle = nport_handle;
|
||||
a.rx_xchg_address = rx_xchg_addr;
|
||||
a.did.b.domain = s_id[2];
|
||||
a.did.b.area = s_id[1];
|
||||
a.did.b.al_pa = s_id[0];
|
||||
a.tx_byte_count = a.tx_len = sizeof(struct fc_els_ls_rjt);
|
||||
a.tx_addr = vha->hw->elsrej.cdma;
|
||||
a.tx_addr = ha->elsrej.cdma;
|
||||
a.vp_idx = vha->vp_idx;
|
||||
a.control_flags = EPD_ELS_RJT;
|
||||
a.ox_id = le16_to_cpu(p->ox_id);
|
||||
a.ox_id = le16_to_cpu(ox_id);
|
||||
|
||||
sid = p->s_id[0] | (p->s_id[1] << 8) | (p->s_id[2] << 16);
|
||||
sid = s_id[0] | (s_id[1] << 8) | (s_id[2] << 16);
|
||||
|
||||
totlen = (le16_to_cpu(p->frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
|
||||
if (le16_to_cpu(p->status_flags) & 0x8000) {
|
||||
totlen = le16_to_cpu(p->trunc_frame_size);
|
||||
totlen = (le16_to_cpu(frame_size) & 0x0fff) - PURX_ELS_HEADER_SIZE;
|
||||
if (le16_to_cpu(status_flags) & 0x8000) {
|
||||
totlen = le16_to_cpu(trunc_frame_size);
|
||||
qla_els_reject_iocb(vha, (*rsp)->qpair, &a);
|
||||
__qla_consume_iocb(vha, pkt, rsp);
|
||||
return;
|
||||
@@ -2600,12 +2629,12 @@ void qla24xx_auth_els(scsi_qla_host_t *vha, void **pkt, struct rsp_que **rsp)
|
||||
purex = &ptr->u.purexinfo;
|
||||
purex->pur_info.pur_sid = a.did;
|
||||
purex->pur_info.pur_bytes_rcvd = totlen;
|
||||
purex->pur_info.pur_rx_xchg_address = le32_to_cpu(p->rx_xchg_addr);
|
||||
purex->pur_info.pur_nphdl = le16_to_cpu(p->nport_handle);
|
||||
purex->pur_info.pur_did.b.domain = p->d_id[2];
|
||||
purex->pur_info.pur_did.b.area = p->d_id[1];
|
||||
purex->pur_info.pur_did.b.al_pa = p->d_id[0];
|
||||
purex->pur_info.vp_idx = p->vp_idx;
|
||||
purex->pur_info.pur_rx_xchg_address = le32_to_cpu(rx_xchg_addr);
|
||||
purex->pur_info.pur_nphdl = le16_to_cpu(nport_handle);
|
||||
purex->pur_info.pur_did.b.domain = d_id[2];
|
||||
purex->pur_info.pur_did.b.area = d_id[1];
|
||||
purex->pur_info.pur_did.b.al_pa = d_id[0];
|
||||
purex->pur_info.vp_idx = vp_idx;
|
||||
|
||||
a.sid = purex->pur_info.pur_did;
|
||||
|
||||
@@ -2989,6 +3018,21 @@ qla28xx_start_scsi_edif(srb_t *sp)
|
||||
struct req_que *req = sp->qpair->req;
|
||||
spinlock_t *lock = sp->qpair->qp_lock_ptr;
|
||||
|
||||
/*
|
||||
* EDIF on 29xx is not supported by this driver yet. The EDIF fast
|
||||
* path builds 64-byte cmd_type_6 IOCBs and advances req->ring_ptr
|
||||
* with a 64-byte stride, which would corrupt the 128-byte extended
|
||||
* request ring that 29xx hardware uses. A proper 29xx EDIF port
|
||||
* requires a cmd_type_6_ext-shaped submission path; until that is
|
||||
* implemented, refuse the command rather than risk ring corruption.
|
||||
*/
|
||||
if (IS_QLA29XX(ha)) {
|
||||
ql_log(ql_log_warn, vha, 0x13ae,
|
||||
"EDIF is not supported on 29xx hardware; failing cmd sp=%p.\n",
|
||||
sp);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
}
|
||||
|
||||
/* Setup device pointers. */
|
||||
cmd = GET_CMD_SP(sp);
|
||||
|
||||
@@ -3129,7 +3173,8 @@ qla28xx_start_scsi_edif(srb_t *sp)
|
||||
* Five DSDs are available in the Continuation
|
||||
* Type 1 IOCB.
|
||||
*/
|
||||
cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req);
|
||||
cont_pkt = qla2x00_prep_cont_type1_iocb(vha,
|
||||
ha, req);
|
||||
cur_dsd = cont_pkt->dsd;
|
||||
avail_dsds = 5;
|
||||
}
|
||||
@@ -3485,12 +3530,18 @@ static void __chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
|
||||
}
|
||||
|
||||
void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
|
||||
srb_t *sp, struct sts_entry_24xx *sts24)
|
||||
srb_t *sp, void *pkt)
|
||||
{
|
||||
struct sts_entry_24xx *sts24 = pkt;
|
||||
struct sts_entry_24xx_ext *stsext = pkt;
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
fc_port_t *fcport = sp->fcport;
|
||||
/* sa_index used by this iocb */
|
||||
struct scsi_cmnd *cmd = GET_CMD_SP(sp);
|
||||
uint32_t handle;
|
||||
uint16_t sa_index;
|
||||
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
handle = (uint32_t)LSW(sts24->handle);
|
||||
|
||||
@@ -3498,8 +3549,12 @@ void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
|
||||
if (cmd->sc_data_direction != DMA_FROM_DEVICE)
|
||||
return;
|
||||
|
||||
return __chk_edif_rx_sa_delete_pending(vha, fcport, handle,
|
||||
le16_to_cpu(sts24->edif_sa_index));
|
||||
if (IS_QLA29XX(ha))
|
||||
sa_index = le16_to_cpu(stsext->read_sa_index);
|
||||
else
|
||||
sa_index = le16_to_cpu(sts24->edif_sa_index);
|
||||
|
||||
return __chk_edif_rx_sa_delete_pending(vha, fcport, handle, sa_index);
|
||||
}
|
||||
|
||||
void qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
|
||||
|
||||
@@ -1442,6 +1442,10 @@ struct vp_ctrl_entry_24xx {
|
||||
uint8_t reserved_5[24];
|
||||
};
|
||||
|
||||
/* vp_idx_map is a 128-bit (16-byte) bitmap selecting target VPs. */
|
||||
#define VP_CTRL_IDX_MAP_BITS \
|
||||
(sizeof_field(struct vp_ctrl_entry_24xx, vp_idx_map) * 8)
|
||||
|
||||
/*
|
||||
* Modify Virtual Port Configuration IOCB
|
||||
*/
|
||||
@@ -1538,7 +1542,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 +1552,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 +1568,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 +1680,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 +1701,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 +1726,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 +2116,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 +2344,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
|
||||
|
||||
@@ -0,0 +1,830 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* QLogic Fibre Channel HBA Driver
|
||||
* Copyright (c) 2026- Marvell.
|
||||
*
|
||||
* See LICENSE.qla2xxx for copyright and licensing details.
|
||||
*/
|
||||
#ifndef __QLA_FW29_H
|
||||
#define __QLA_FW29_H
|
||||
|
||||
#include "qla_fw.h"
|
||||
|
||||
/* Control Flags 2 common for cmd6 and 7 */
|
||||
#define CF2_VMID_ENABLE BIT_0
|
||||
#define CF2_CSCTL_PRIORITY_TAG BIT_1
|
||||
#define CF2_NO_TRNF_READY_ENABLE BIT_2
|
||||
#define CF2_RX_ID_ENABLE BIT_3
|
||||
|
||||
/*
|
||||
* vp_index layout for 29xx extended command IOCBs
|
||||
* (cmd_type_6_ext, cmd_type_7_ext, cmd_type_crc_2_ext, ...):
|
||||
* bits [8:0] - VP index (9 bits)
|
||||
* bits [15:9] - reserved, must be zero
|
||||
* Access on a host-endian value via le16_to_cpu(vp_index) & CMD_EXT_VP_INDEX_MASK.
|
||||
*/
|
||||
#define CMD_EXT_VP_INDEX_MASK 0x01ff
|
||||
|
||||
/*
|
||||
* Combined vp_index/sof_type field layout (used by ELS and ABTS ext IOCBs):
|
||||
* bits [8:0] - VP index (9 bits)
|
||||
* bits [11:9] - reserved
|
||||
* bits [15:12] - SOF type (4 bits)
|
||||
*/
|
||||
#define EXT_VP_SOF_VP_INDEX_MASK 0x01ff
|
||||
#define EXT_VP_SOF_SOF_TYPE_SHIFT 12
|
||||
#define EXT_VP_SOF_SOF_TYPE_MASK 0xf000
|
||||
|
||||
static inline u16 qla_ext_get_vp_index(__le16 vp_sof)
|
||||
{
|
||||
return le16_to_cpu(vp_sof) & EXT_VP_SOF_VP_INDEX_MASK;
|
||||
}
|
||||
|
||||
static inline u16 qla_ext_get_sof_type(__le16 vp_sof)
|
||||
{
|
||||
return (le16_to_cpu(vp_sof) >> EXT_VP_SOF_SOF_TYPE_SHIFT) & 0xf;
|
||||
}
|
||||
|
||||
static inline __le16 qla_ext_build_vp_sof(u16 vp_idx, u16 sof_type)
|
||||
{
|
||||
return cpu_to_le16((vp_idx & EXT_VP_SOF_VP_INDEX_MASK) |
|
||||
((sof_type & 0xf) << EXT_VP_SOF_SOF_TYPE_SHIFT));
|
||||
}
|
||||
|
||||
/*
|
||||
* Combined vp_idx/vp_status field layout (vp_rpt_id_entry_24xx_ext):
|
||||
* bits [8:0] - VP index (9 bits)
|
||||
* bits [15:9] - VP status (7 bits)
|
||||
*/
|
||||
#define EXT_VP_STATUS_VP_INDEX_MASK 0x01ff
|
||||
#define EXT_VP_STATUS_VP_STATUS_SHIFT 9
|
||||
#define EXT_VP_STATUS_VP_STATUS_MASK 0xfe00
|
||||
|
||||
/*
|
||||
* ISP queue - command entry structure definition.
|
||||
*/
|
||||
#define NUM_CMD67_DSDS 4
|
||||
struct cmd_type_6_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
|
||||
__le16 fcp_rsp_dsd_len; /* FCP_RSP DSD length. */
|
||||
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
|
||||
__le16 control_flags; /* Control flags. */
|
||||
|
||||
__le16 fcp_cmnd_dseg_len; /* Data segment length. */
|
||||
/* Data segment address. */
|
||||
__le64 fcp_cmnd_dseg_address __packed;
|
||||
/* Data segment address. */
|
||||
__le64 fcp_rsp_dseg_address __packed;
|
||||
|
||||
__le32 byte_count; /* Total byte count. */
|
||||
__le16 control_flags_2; /* Control flags 2. */
|
||||
|
||||
__le16 vp_index; /* VP Index 9bits*/
|
||||
__le32 fburstlen_rxid; /* First Burst length/RX ID */
|
||||
__le16 io_tag; /* I/O Tag */
|
||||
uint8_t vl_n_fctl; /* VL (7-4) | RSVD (3-2) | F_CTL [17] (1) | RSVD (0) */
|
||||
uint8_t prtag_csctl; /* Priority Tag or CS_CTL */
|
||||
__le32 src_vm_id; /* Source VM ID */
|
||||
uint8_t reserved_2[16]; /* Reserved */
|
||||
struct dsd64 dsd[NUM_CMD67_DSDS]; /* Data Segment Descriptors */
|
||||
};
|
||||
|
||||
struct cmd_type_7_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
uint32_t handle; /* System handle. */
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
uint16_t reserved_1;
|
||||
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
|
||||
__le16 task_mgmt_flags; /* Task management flags. */
|
||||
|
||||
uint8_t task;
|
||||
uint8_t crn;
|
||||
uint8_t fcp_cdb[MAX_CMDSZ]; /* SCSI command words. */
|
||||
__le32 byte_count; /* Total byte count. */
|
||||
__le16 ctrl_flags_2; /* Control flags 2 */
|
||||
__le16 vp_index; /* VP Index 9bits*/
|
||||
__le32 rx_id; /* Receive Exchange ID */
|
||||
__le16 io_tag; /* I/O Tag */
|
||||
uint8_t vl_n_fctl; /* VL (7-4) | RSVD (3-2) | F_CTL [17] (1) | RSVD (0) */
|
||||
uint8_t reserved_3[21]; /* Reserved */
|
||||
struct dsd64 dsd[NUM_CMD67_DSDS]; /* Data Segment Descriptors */
|
||||
};
|
||||
|
||||
/*
|
||||
* Inline data-DSD capacity of the 29xx cmd_type_crc_2_ext IOCB. Unlike
|
||||
* cmd_type_6_ext / cmd_type_7_ext (which carry NUM_CMD67_DSDS inline DSDs),
|
||||
* CRC_2 places the bulk of its DSDs in the separate CRC-context DMA; only
|
||||
* a single data_dsd is carried inline in both the u.nobundling and
|
||||
* u.bundling variants. Use this constant wherever the IOCB-reservation
|
||||
* calculator needs the CRC_2 ext inline capacity so it stays in sync with
|
||||
* the firmware-facing layout below.
|
||||
*/
|
||||
#define NUM_CRC2_EXT_INLINE_DSDS 1
|
||||
|
||||
struct cmd_type_crc_2_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
__le16 fcp_rsp_dseg_len; /* FCP_RSP DSD length. */
|
||||
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
|
||||
__le16 control_flags_1; /* Control flags. */
|
||||
__le16 fcp_cmnd_dseg_len; /* Data segment length. */
|
||||
|
||||
__le64 fcp_cmnd_dseg_address __packed;
|
||||
/* Data segment address. */
|
||||
__le64 fcp_rsp_dseg_address __packed;
|
||||
|
||||
__le32 byte_count; /* Total byte count. */
|
||||
|
||||
__le16 control_flags_2; /* Control flags - 2 */
|
||||
__le16 vp_index; /* VP Index (bits [8:0]); bits [15:9] reserved.
|
||||
* See CMD_EXT_VP_INDEX_MASK.
|
||||
*/
|
||||
|
||||
uint32_t reserved_1;
|
||||
|
||||
__le16 iocb_tag; /* Unused */
|
||||
__le16 vl_prio; /* Bit 1 - F_CTL, Bits 4-7 VL, rest are rsvd */
|
||||
|
||||
uint32_t reserved_2; /* 3C-3F offset */
|
||||
|
||||
__le32 ref_tag;
|
||||
uint8_t ref_tag_mask[4]; /* Validation/Replacement Mask*/
|
||||
|
||||
__le16 app_tag;
|
||||
uint8_t app_tag_mask[2]; /* Validation/Replacement Mask*/
|
||||
|
||||
__le16 blk_size; /* Data size in bytes */
|
||||
__le16 prot_opts; /* Requested Data Protection Mode */
|
||||
|
||||
__le32 tot_byte_count; /* Total byte count/ total data
|
||||
* transfer count
|
||||
*/
|
||||
union {
|
||||
struct {
|
||||
uint32_t reserved_1; /* offset 54 */
|
||||
uint16_t reserved_2;
|
||||
__le16 guard_seed; /* offset 5A */
|
||||
struct dsd64 data_dsd[1];
|
||||
uint32_t reserved_5[2];
|
||||
uint32_t reserved_6;
|
||||
} nobundling;
|
||||
struct {
|
||||
__le32 dif_byte_count; /* Total DIF byte
|
||||
* count
|
||||
*/
|
||||
__le16 dseg_count; /* Data segment count */
|
||||
__le16 guard_seed; /* Initial Guard Seed */
|
||||
struct dsd64 data_dsd[1];
|
||||
struct dsd64 dif_dsd;
|
||||
} bundling;
|
||||
} u;
|
||||
uint8_t reserved_3[12]; /* MUST be set to 0. */
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - status entry structure definition.
|
||||
*/
|
||||
struct sts_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
__le16 ox_id; /* OX_ID used by the firmware. */
|
||||
|
||||
__le32 residual_len; /* FW calc residual transfer length. */
|
||||
|
||||
union {
|
||||
__le16 reserved_1;
|
||||
__le16 nvme_rsp_pyld_len;
|
||||
} u1;
|
||||
|
||||
__le16 state_flags; /* State flags. */
|
||||
|
||||
__le16 read_sa_index;
|
||||
__le16 wr_sa_index;
|
||||
uint8_t reserved_2[8];
|
||||
uint8_t act_dif[8];
|
||||
uint8_t exp_dif[8];
|
||||
union {
|
||||
struct {
|
||||
__le32 rsp_data_len_dma; /* FCP response data length */
|
||||
uint8_t reserved_3[76];
|
||||
};
|
||||
struct {
|
||||
uint8_t nvme_ersp_data[32];
|
||||
uint8_t reserved_4[48];
|
||||
};
|
||||
struct {
|
||||
__le32 bid_rd_rsp_residual_count; /* BID read rsp residual cnt */
|
||||
__le16 retry_delay_timer; /* Retry delay timer. */
|
||||
__le16 scsi_status; /* SCSI status. */
|
||||
__le32 rsp_residual_count; /* FCP RSP residual count. */
|
||||
__le32 sense_len; /* FCP SENSE length. */
|
||||
__le32 rsp_data_len_ndma; /* FCP response data length */
|
||||
uint8_t data[60]; /* FCP rsp/sense information */
|
||||
};
|
||||
} u2;
|
||||
|
||||
/*
|
||||
* If DIF Error is set in comp_status, these additional fields are
|
||||
* defined:
|
||||
*
|
||||
* !!! NOTE: Firmware sends expected/actual DIF data in big endian
|
||||
* format; but all of the "data" field gets swab32-d in the beginning
|
||||
* of qla2900_status_entry().
|
||||
*
|
||||
* &data[10] : uint8_t report_runt_bg[2]; - computed guard
|
||||
* &data[12] : uint8_t actual_dif[8]; - DIF Data received
|
||||
* &data[20] : uint8_t expected_dif[8]; - DIF Data computed
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - marker entry structure definition.
|
||||
*/
|
||||
struct mrk_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t handle_count; /* Handle count. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
uint8_t modifier; /* Modifier (7-0). */
|
||||
uint8_t reserved_1;
|
||||
|
||||
__le16 vp_index; /* VP Index. 9bits*/
|
||||
uint16_t reserved_3;
|
||||
|
||||
uint8_t lun[8]; /* FCP LUN (BE). */
|
||||
uint8_t reserved_4[104];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - CT Pass-Through entry structure definition.
|
||||
*/
|
||||
#define NUM_CT_DSDS 5
|
||||
struct ct_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System Defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
__le16 cmd_dsd_count;
|
||||
|
||||
__le16 vp_index; /* vp index 9 bits*/
|
||||
|
||||
__le16 timeout; /* Command timeout. */
|
||||
uint16_t reserved_2;
|
||||
|
||||
__le16 rsp_dsd_count;
|
||||
|
||||
uint8_t reserved_3[10];
|
||||
uint8_t reserved_4[28]; /* Reserved. */
|
||||
|
||||
__le32 rsp_byte_count;
|
||||
__le32 cmd_byte_count;
|
||||
struct dsd64 dsd[NUM_CT_DSDS]; /* Data Segment Descriptors */
|
||||
};
|
||||
|
||||
/*
|
||||
* 29xx extended Link Service pass-through request IOCB (128 bytes).
|
||||
*
|
||||
* Same wire purpose as the 64-byte struct pt_ls4_request used on 24xx-class
|
||||
* adapters, but laid out for the 128-byte 29xx request ring:
|
||||
* - vp_index widened to __le16 (bits [8:0] meaningful, see
|
||||
* CMD_EXT_VP_INDEX_MASK).
|
||||
* - reserved area expanded to 32 bytes between exchange_address and
|
||||
* rx_byte_count.
|
||||
* - inline DSD capacity grown from 2 to 5.
|
||||
* Header through 'tx_dseg_count' (offset 14) and the control_flags /
|
||||
* exchange_address fields keep the same offsets as struct pt_ls4_request,
|
||||
* so common code can populate them via either type once IS_QLA29XX(ha) is
|
||||
* branched for the layout-divergent fields.
|
||||
*/
|
||||
#define NUM_PT_LS4_EXT_DSDS 5
|
||||
struct pt_ls4_request_ext {
|
||||
uint8_t entry_type;
|
||||
uint8_t entry_count;
|
||||
uint8_t sys_define;
|
||||
uint8_t entry_status;
|
||||
uint32_t handle;
|
||||
__le16 status;
|
||||
__le16 nport_handle;
|
||||
__le16 tx_dseg_count;
|
||||
__le16 vp_index; /* VP Index 9 bits; see CMD_EXT_VP_INDEX_MASK */
|
||||
__le16 timeout;
|
||||
__le16 control_flags; /* CF_LS4_* (see struct pt_ls4_request) */
|
||||
__le16 rx_dseg_count;
|
||||
__le16 rsvd2;
|
||||
__le32 exchange_address;
|
||||
uint8_t rsvd3[32];
|
||||
__le32 rx_byte_count;
|
||||
__le32 tx_byte_count;
|
||||
struct dsd64 dsd[NUM_PT_LS4_EXT_DSDS];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - PUREX IOCB entry structure definition
|
||||
*/
|
||||
struct purex_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
__le16 reserved1;
|
||||
__le16 vp_idx; /* VP index 9 bits*/
|
||||
|
||||
__le16 status_flags;
|
||||
__le16 nport_handle;
|
||||
|
||||
__le16 frame_size;
|
||||
__le16 trunc_frame_size;
|
||||
|
||||
__le32 rx_xchg_addr;
|
||||
|
||||
uint8_t d_id[3];
|
||||
uint8_t r_ctl;
|
||||
|
||||
uint8_t s_id[3];
|
||||
uint8_t cs_ctl;
|
||||
|
||||
uint8_t f_ctl[3];
|
||||
uint8_t type;
|
||||
|
||||
__le16 seq_cnt;
|
||||
uint8_t df_ctl;
|
||||
uint8_t seq_id;
|
||||
|
||||
__le16 rx_id;
|
||||
__le16 ox_id;
|
||||
__le32 param;
|
||||
|
||||
uint8_t els_frame_payload[84];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - ELS Pass-Through entry structure definition.
|
||||
* ELS_EXT_EST_SOFI*: 4-bit sof_type for extended IOCBs (qla_fw.h EST_SOFI*
|
||||
* is for els_entry_24xx byte layout).
|
||||
*/
|
||||
#define ELS_EXT_EST_SOFI3 (1 << 1)
|
||||
#define ELS_EXT_EST_SOFI2 (3 << 3)
|
||||
|
||||
struct els_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System Defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 comp_status; /* response only */
|
||||
__le16 nport_handle;
|
||||
|
||||
__le16 tx_dsd_count;
|
||||
|
||||
__le16 vp_index_sof; /* bits [8:0]=VP index, [15:12]=SOF type */
|
||||
|
||||
__le32 rx_xchg_address; /* Receive exchange address. */
|
||||
__le16 rx_dsd_count;
|
||||
|
||||
uint8_t opcode;
|
||||
uint8_t reserved_2;
|
||||
|
||||
uint8_t d_id[3];
|
||||
uint8_t s_id[3];
|
||||
|
||||
__le16 control_flags; /* Control flags. */
|
||||
|
||||
union {
|
||||
struct {
|
||||
__le32 rx_byte_count;
|
||||
__le32 tx_byte_count;
|
||||
|
||||
__le64 tx_address __packed; /* DSD 0 address. */
|
||||
__le32 tx_len; /* DSD 0 length. */
|
||||
|
||||
__le64 rx_address __packed; /* DSD 1 address. */
|
||||
__le32 rx_len; /* DSD 1 length. */
|
||||
};
|
||||
struct {
|
||||
__le32 total_byte_count;
|
||||
__le32 error_subcode_1;
|
||||
__le32 error_subcode_2;
|
||||
__le32 error_subcode_3;
|
||||
uint8_t reserved_3[16];
|
||||
};
|
||||
};
|
||||
uint8_t reserved_4[64];
|
||||
};
|
||||
|
||||
struct els_sts_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System Defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
__le32 handle; /* System handle. */
|
||||
|
||||
__le16 comp_status;
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
__le16 reserved_1;
|
||||
|
||||
__le16 vp_index_sof; /* bits [8:0]=VP index, [15:12]=SOF type */
|
||||
|
||||
__le32 rx_xchg_address; /* Receive exchange address. */
|
||||
__le16 reserved_2;
|
||||
|
||||
uint8_t opcode;
|
||||
uint8_t reserved_3;
|
||||
|
||||
uint8_t d_id[3];
|
||||
uint8_t s_id[3];
|
||||
|
||||
__le16 control_flags; /* Control flags. */
|
||||
__le32 total_byte_count;
|
||||
__le32 error_subcode_1;
|
||||
__le32 error_subcode_2;
|
||||
__le32 error_subcode_3;
|
||||
|
||||
uint8_t reserved_4[80];
|
||||
};
|
||||
|
||||
struct logio_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
__le16 control_flags; /* Control flags. */
|
||||
|
||||
__le16 vp_index; /* VP Index 9bits*/
|
||||
|
||||
uint8_t port_id[3]; /* PortID of destination port. */
|
||||
|
||||
uint8_t rsp_size; /* Response size in 32bit words. */
|
||||
|
||||
__le32 io_parameter[11]; /* General I/O parameters. */
|
||||
uint8_t reserved_2[64]; /* Reserved*/
|
||||
};
|
||||
|
||||
struct tsk_mgmt_entry_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t handle_count; /* Handle count. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
|
||||
__le16 reserved_1;
|
||||
|
||||
__le16 delay; /* Activity delay in seconds. */
|
||||
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
struct scsi_lun lun; /* FCP LUN (BE). */
|
||||
|
||||
__le32 control_flags; /* Control Flags. */
|
||||
|
||||
__le16 vp_index; /* VP Index 9bits */
|
||||
|
||||
uint8_t reserved_3[98];
|
||||
};
|
||||
|
||||
struct abort_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t handle_count; /* Handle count. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
union {
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 comp_status; /* Completion status. */
|
||||
};
|
||||
|
||||
__le16 options; /* Options. */
|
||||
|
||||
uint32_t handle_to_abort; /* System handle to abort. */
|
||||
|
||||
__le16 req_que_no;
|
||||
|
||||
__le16 vp_index; /* VP Index 9bits*/
|
||||
u8 reserved_2[4];
|
||||
union {
|
||||
struct {
|
||||
__le16 abts_rty_cnt;
|
||||
__le16 rsp_timeout;
|
||||
} drv;
|
||||
struct {
|
||||
u8 ba_rjt_vendorUnique;
|
||||
u8 ba_rjt_reasonCodeExpl;
|
||||
u8 ba_rjt_reasonCode;
|
||||
u8 reserved_3;
|
||||
} fw;
|
||||
};
|
||||
u8 reserved_4[100];
|
||||
};
|
||||
|
||||
struct abts_entry_24xx_ext {
|
||||
uint8_t entry_type;
|
||||
uint8_t entry_count;
|
||||
uint8_t handle_count;
|
||||
uint8_t entry_status;
|
||||
|
||||
__le32 handle; /* type 0x55 only */
|
||||
|
||||
__le16 comp_status; /* type 0x55 only */
|
||||
__le16 nport_handle; /* type 0x54 only */
|
||||
|
||||
__le16 control_flags; /* type 0x55 only */
|
||||
__le16 vp_idx_sof; /* bits [8:0]=VP index, [15:12]=SOF type */
|
||||
|
||||
__le32 rx_xch_addr;
|
||||
|
||||
uint8_t d_id[3];
|
||||
uint8_t r_ctl;
|
||||
|
||||
uint8_t s_id[3];
|
||||
uint8_t cs_ctl;
|
||||
|
||||
uint8_t f_ctl[3];
|
||||
uint8_t type;
|
||||
|
||||
__le16 seq_cnt;
|
||||
uint8_t df_ctl;
|
||||
uint8_t seq_id;
|
||||
|
||||
__le16 rx_id;
|
||||
__le16 ox_id;
|
||||
|
||||
__le32 param;
|
||||
|
||||
union {
|
||||
struct {
|
||||
__le32 subcode3;
|
||||
__le32 rsvd;
|
||||
__le32 subcode1;
|
||||
__le32 subcode2;
|
||||
} error;
|
||||
struct {
|
||||
__le16 rsrvd1;
|
||||
uint8_t last_seq_id;
|
||||
uint8_t seq_id_valid;
|
||||
__le16 aborted_rx_id;
|
||||
__le16 aborted_ox_id;
|
||||
__le16 high_seq_cnt;
|
||||
__le16 low_seq_cnt;
|
||||
} ba_acc;
|
||||
struct {
|
||||
uint8_t vendor_unique;
|
||||
uint8_t explanation;
|
||||
uint8_t reason;
|
||||
} ba_rjt;
|
||||
} payload;
|
||||
|
||||
__le32 rx_xch_addr_to_abort;
|
||||
uint8_t reserved_2[64];
|
||||
} __packed;
|
||||
/*
|
||||
* Virtual Port Control IOCB
|
||||
*/
|
||||
struct vp_ctrl_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 vp_idx_failed;
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
|
||||
__le16 command;
|
||||
|
||||
__le16 vp_count;
|
||||
|
||||
uint8_t vp_idx_map[16];
|
||||
__le16 flags;
|
||||
__le16 id;
|
||||
uint16_t reserved_4;
|
||||
__le16 hopct;
|
||||
uint8_t reserved_5[88];
|
||||
};
|
||||
|
||||
/*
|
||||
* Modify Virtual Port Configuration IOCB
|
||||
*/
|
||||
struct vp_config_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t handle_count;
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
|
||||
__le16 flags;
|
||||
|
||||
__le16 comp_status; /* Completion status. */
|
||||
|
||||
uint8_t command;
|
||||
|
||||
uint8_t vp_count;
|
||||
|
||||
uint8_t vp_index1;
|
||||
uint8_t vp_index2;
|
||||
|
||||
uint8_t options_idx1;
|
||||
uint8_t hard_address_idx1;
|
||||
uint16_t reserved_vp1;
|
||||
uint8_t port_name_idx1[WWN_SIZE];
|
||||
uint8_t node_name_idx1[WWN_SIZE];
|
||||
|
||||
uint8_t options_idx2;
|
||||
uint8_t hard_address_idx2;
|
||||
uint16_t reserved_vp2;
|
||||
uint8_t port_name_idx2[WWN_SIZE];
|
||||
uint8_t node_name_idx2[WWN_SIZE];
|
||||
__le16 id;
|
||||
uint16_t reserved_4;
|
||||
__le16 hopct;
|
||||
uint8_t reserved_5[66];
|
||||
};
|
||||
|
||||
struct vp_rpt_id_entry_24xx_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
__le32 resv1;
|
||||
uint8_t vp_acquired;
|
||||
uint8_t vp_setup;
|
||||
__le16 vp_idx_status; /* bits [8:0]=VP index, [15:9]=VP status */
|
||||
|
||||
uint8_t port_id[3];
|
||||
uint8_t format;
|
||||
union {
|
||||
struct vp_rpt_id_ext_f1 {
|
||||
/* format 1 fabric */
|
||||
uint8_t vpstat1_subcode; /* vp_status=1 subcode */
|
||||
uint8_t flags;
|
||||
|
||||
__le16 fip_flags;
|
||||
uint8_t rsv2[12];
|
||||
|
||||
uint8_t ls_rjt_vendor;
|
||||
uint8_t ls_rjt_explanation;
|
||||
uint8_t ls_rjt_reason;
|
||||
uint8_t rsv3;
|
||||
__le16 rsv8;
|
||||
__le16 flogi_acc_payload_size; /* bits [8:0] meaningful */
|
||||
uint8_t port_name[8];
|
||||
uint8_t node_name[8];
|
||||
__le16 bbcr;
|
||||
uint8_t reserved_5[6];
|
||||
} f1;
|
||||
struct vp_rpt_id_ext_f2 { /* format 2: N2N direct connect */
|
||||
uint8_t vpstat1_subcode;
|
||||
uint8_t flags;
|
||||
__le16 fip_flags;
|
||||
uint8_t rsv2[12];
|
||||
|
||||
uint8_t ls_rjt_vendor;
|
||||
uint8_t ls_rjt_explanation;
|
||||
uint8_t ls_rjt_reason;
|
||||
uint8_t rsv3[5];
|
||||
|
||||
uint8_t port_name[8];
|
||||
uint8_t node_name[8];
|
||||
__le16 bbcr;
|
||||
uint8_t reserved_5[2];
|
||||
uint8_t remote_nport_id[4];
|
||||
} f2;
|
||||
} u;
|
||||
uint8_t reserved_end[64];
|
||||
};
|
||||
|
||||
/*
|
||||
* ISP queue - 64-Bit addressing, continuation entry structure definition
|
||||
* for the 29xx extended (128-byte) IOCB ring. Mirrors cont_a64_entry_t
|
||||
* but carries 10 DSDs per entry instead of 5.
|
||||
*/
|
||||
#define NUM_CONT1_DSDS 10
|
||||
struct cont_a64_entry_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
uint32_t reserved;
|
||||
struct dsd64 dsd[NUM_CONT1_DSDS];
|
||||
};
|
||||
|
||||
/*
|
||||
* 29xx extended Command Type FC-NVMe IOCB (128 bytes).
|
||||
*
|
||||
* The header layout up through 'byte_count' (offset 48) is identical to the
|
||||
* 64-byte struct cmd_nvme used by 24xx-class adapters, so common code can
|
||||
* populate those fields via either type. Fields beyond 'byte_count' diverge:
|
||||
* 29xx adds control_flags_2/vp_index/first_burst_rx_id/io_tag/..., drops
|
||||
* port_id[3]+vp_index(byte), and carries NUM_NVME_DSDS inline DSDs.
|
||||
*/
|
||||
#define NUM_NVME_DSDS 4
|
||||
struct cmd_nvme_ext {
|
||||
uint8_t entry_type; /* Entry type. */
|
||||
uint8_t entry_count; /* Entry count. */
|
||||
uint8_t sys_define; /* System defined. */
|
||||
uint8_t entry_status; /* Entry Status. */
|
||||
|
||||
uint32_t handle; /* System handle. */
|
||||
__le16 nport_handle; /* N_PORT handle. */
|
||||
__le16 timeout; /* Command timeout. */
|
||||
|
||||
__le16 dseg_count; /* Data segment count. */
|
||||
__le16 nvme_rsp_dsd_len; /* NVMe RSP DSD length */
|
||||
|
||||
uint64_t rsvd;
|
||||
|
||||
__le16 control_flags; /* Control Flags (see struct cmd_nvme) */
|
||||
__le16 nvme_cmnd_dseg_len; /* Data segment length. */
|
||||
|
||||
__le64 nvme_cmnd_dseg_address __packed; /* Data segment address. */
|
||||
|
||||
__le64 nvme_rsp_dseg_address __packed; /* Data segment address. */
|
||||
|
||||
__le32 byte_count; /* Total byte count. */
|
||||
|
||||
__le16 control_flags_2;
|
||||
/*
|
||||
* vp_index layout matches the other 29xx extended IOCBs: only bits
|
||||
* [8:0] are meaningful (see CMD_EXT_VP_INDEX_MASK).
|
||||
*/
|
||||
__le16 vp_index;
|
||||
__le32 first_burst_rx_id;
|
||||
__le16 io_tag;
|
||||
uint8_t vl_n_fctl; /* VL(7:4) | RSVD(3:2) | F_CTL[17](1) | RSVD(0) */
|
||||
uint8_t prtag_csctl; /* Priority Tag or CS_CTL */
|
||||
__le32 src_vm_id; /* Source VM ID */
|
||||
uint8_t reserved_2[16];
|
||||
|
||||
struct dsd64 nvme_dsd[NUM_NVME_DSDS];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -38,6 +38,7 @@ extern void qla24xx_update_fw_options(scsi_qla_host_t *);
|
||||
extern int qla2x00_load_risc(struct scsi_qla_host *, uint32_t *);
|
||||
extern int qla24xx_load_risc(scsi_qla_host_t *, uint32_t *);
|
||||
extern int qla81xx_load_risc(scsi_qla_host_t *, uint32_t *);
|
||||
extern int qla29xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr);
|
||||
|
||||
extern int qla2x00_perform_loop_resync(scsi_qla_host_t *);
|
||||
extern int qla2x00_loop_resync(scsi_qla_host_t *);
|
||||
@@ -135,7 +136,7 @@ void qla_edif_sadb_release(struct qla_hw_data *ha);
|
||||
int qla_edif_sadb_build_free_pool(struct qla_hw_data *ha);
|
||||
void qla_edif_sadb_release_free_pool(struct qla_hw_data *ha);
|
||||
void qla_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha,
|
||||
srb_t *sp, struct sts_entry_24xx *sts24);
|
||||
srb_t *sp, void *pkt);
|
||||
void qlt_chk_edif_rx_sa_delete_pending(scsi_qla_host_t *vha, fc_port_t *fcport,
|
||||
struct ctio7_from_24xx *ctio);
|
||||
void qla2x00_release_all_sadb(struct scsi_qla_host *vha, struct fc_port *fcport);
|
||||
@@ -265,8 +266,7 @@ extern int qla24xx_modify_vp_config(scsi_qla_host_t *);
|
||||
extern int qla2x00_send_change_request(scsi_qla_host_t *, uint16_t, uint16_t);
|
||||
extern void qla2x00_vp_stop_timer(scsi_qla_host_t *);
|
||||
extern int qla24xx_configure_vhba (scsi_qla_host_t *);
|
||||
extern void qla24xx_report_id_acquisition(scsi_qla_host_t *,
|
||||
struct vp_rpt_id_entry_24xx *);
|
||||
extern void qla24xx_report_id_acquisition(scsi_qla_host_t *vha, void *pkt);
|
||||
extern void qla2x00_do_dpc_all_vps(scsi_qla_host_t *);
|
||||
extern int qla24xx_vport_create_req_sanity_check(struct fc_vport *);
|
||||
extern scsi_qla_host_t *qla24xx_create_vhost(struct fc_vport *);
|
||||
@@ -294,9 +294,11 @@ void qla_adjust_buf(struct scsi_qla_host *);
|
||||
* Global Function Prototypes in qla_iocb.c source file.
|
||||
*/
|
||||
void qla_els_pt_iocb(struct scsi_qla_host *vha,
|
||||
struct els_entry_24xx *pkt, struct qla_els_pt_arg *a);
|
||||
void *pkt, struct qla_els_pt_arg *a);
|
||||
cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha,
|
||||
struct req_que *que);
|
||||
struct qla_hw_data *ha, struct req_que *que);
|
||||
struct cont_a64_entry_ext *qla2900_prep_cont_type1_iocb(scsi_qla_host_t *vha,
|
||||
struct req_que *req);
|
||||
extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
|
||||
extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
|
||||
extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
|
||||
@@ -336,7 +338,7 @@ void qla2x00_els_dcmd2_iocb_timeout(void *data);
|
||||
* Global Function Prototypes in qla_mbx.c source file.
|
||||
*/
|
||||
extern int
|
||||
qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
|
||||
qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t, int);
|
||||
|
||||
extern int
|
||||
qla2x00_dump_ram(scsi_qla_host_t *, dma_addr_t, uint32_t, uint32_t);
|
||||
@@ -580,6 +582,12 @@ extern int qla2xxx_read_remote_register(scsi_qla_host_t *, uint32_t,
|
||||
extern int qla2xxx_write_remote_register(scsi_qla_host_t *, uint32_t,
|
||||
uint32_t);
|
||||
void qla_no_op_mb(struct scsi_qla_host *vha);
|
||||
extern int qla29xx_flash_block_read(scsi_qla_host_t *vha, dma_addr_t req_dma,
|
||||
uint32_t flash_addr, uint32_t flash_size,
|
||||
uint16_t reg_code, uint16_t opt);
|
||||
extern int qla29xx_flash_block_write(scsi_qla_host_t *vha, dma_addr_t req_dma,
|
||||
uint32_t flash_addr, uint32_t flash_size,
|
||||
uint16_t reg_code, uint16_t opt);
|
||||
|
||||
/*
|
||||
* Global Function Prototypes in qla_isr.c source file.
|
||||
@@ -682,7 +690,19 @@ struct purex_item *qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha,
|
||||
void **pkt, struct rsp_que **rsp, bool is_purls, bool byte_order);
|
||||
int qla_mailbox_passthru(scsi_qla_host_t *vha, uint16_t *mbx_in,
|
||||
uint16_t *mbx_out);
|
||||
|
||||
void *qla29xx_read_optrom_data(struct scsi_qla_host *vha,
|
||||
uint16_t reg_code, uint16_t opts,
|
||||
void *buf, uint32_t offset,
|
||||
uint32_t length);
|
||||
extern int qla29xx_write_optrom_data(struct scsi_qla_host *vha,
|
||||
uint16_t reg_code, uint16_t opts,
|
||||
void *buf, uint32_t offset,
|
||||
uint32_t length);
|
||||
extern int qla29xx_mpi_optrom_data(struct scsi_qla_host *vha, uint16_t opts,
|
||||
void *buf, uint32_t offset, uint32_t length,
|
||||
enum qla29xx_mpi_optrom_op op);
|
||||
extern int qla29xx_load_dump_mpi(scsi_qla_host_t *vha, uint16_t opt,
|
||||
uint32_t mpi_addr, uint32_t dlen, dma_addr_t req_dma);
|
||||
/*
|
||||
* Global Function Prototypes in qla_dbg.c source file.
|
||||
*/
|
||||
@@ -968,10 +988,8 @@ extern void qla24xx_process_purex_list(struct purex_list *);
|
||||
extern void qla2x00_dfs_create_rport(scsi_qla_host_t *vha, struct fc_port *fp);
|
||||
extern void qla2x00_dfs_remove_rport(scsi_qla_host_t *vha, struct fc_port *fp);
|
||||
extern void qla_wait_nvme_release_cmd_kref(srb_t *sp);
|
||||
extern void qla_nvme_abort_set_option
|
||||
(struct abort_entry_24xx *abt, srb_t *sp);
|
||||
extern void qla_nvme_abort_process_comp_status
|
||||
(struct abort_entry_24xx *abt, srb_t *sp);
|
||||
extern void qla_nvme_abort_set_option(void *pkt, srb_t *sp);
|
||||
extern void qla_nvme_abort_process_comp_status(void *pkt, srb_t *sp);
|
||||
struct scsi_qla_host *qla_find_host_by_vp_idx(struct scsi_qla_host *vha,
|
||||
uint16_t vp_idx);
|
||||
|
||||
|
||||
+132
-44
@@ -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;
|
||||
}
|
||||
|
||||
+824
-106
File diff suppressed because it is too large
Load Diff
@@ -54,6 +54,103 @@ 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 u8
|
||||
qla_calc_queue_count(u16 msix_count)
|
||||
{
|
||||
/*
|
||||
* Request/response queues are bounded by the MSI-X vector count less
|
||||
* the mailbox vector. These counters are u8, so a board advertising
|
||||
* e.g. 257 vectors would truncate msix_count - 1 (256) to 0 and hand
|
||||
* kzalloc_objs() a zero count (ZERO_SIZE_PTR), faulting on the first
|
||||
* ha->req_q_map[0] store. Clamp into [1, QLA_MAX_QUEUES - 1].
|
||||
*/
|
||||
return clamp_t(u16, msix_count - 1, 1, QLA_MAX_QUEUES - 1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
qla2x00_poll(struct rsp_que *rsp)
|
||||
{
|
||||
@@ -358,17 +455,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 +850,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;
|
||||
}
|
||||
}
|
||||
|
||||
+1140
-279
File diff suppressed because it is too large
Load Diff
+469
-279
File diff suppressed because it is too large
Load Diff
+389
-112
@@ -618,7 +618,7 @@ mbx_done:
|
||||
|
||||
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 @@ again:
|
||||
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 @@ again:
|
||||
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 @@ again:
|
||||
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 @@ again:
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
@@ -2262,6 +2276,8 @@ qla2x00_get_firmware_state(scsi_qla_host_t *vha, uint16_t *states)
|
||||
if (!ha->flags.fw_started)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
memset(&mc, 0, sizeof(mc));
|
||||
|
||||
mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
|
||||
mcp->out_mb = MBX_0;
|
||||
if (IS_FWI2_CAPABLE(vha->hw))
|
||||
@@ -2269,7 +2285,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 +2303,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 +2311,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 +2575,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 +2590,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 +2610,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 +2682,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 +2853,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 +2862,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 +2881,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 +2905,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 +3100,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 +3326,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 +3358,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 +3402,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 +3414,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 +3428,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 +3441,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 +3468,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 +3508,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 +3602,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 +3642,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 +3913,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 +4088,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 +4107,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 +4139,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 +4235,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 +4256,22 @@ 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) {
|
||||
if (test_bit(VPORT_DELETE, &vp->dpc_flags))
|
||||
break;
|
||||
found = 1;
|
||||
atomic_inc(&vp->vref_count);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -4211,7 +4280,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha,
|
||||
if (!found)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&ha->vport_slock, flags);
|
||||
qla_update_host_map(vp, id);
|
||||
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
||||
|
||||
/*
|
||||
* Cannot configure here as we are still sitting on the
|
||||
@@ -4220,6 +4291,10 @@ 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);
|
||||
|
||||
spin_lock_irqsave(&ha->vport_slock, flags);
|
||||
atomic_dec(&vp->vref_count);
|
||||
spin_unlock_irqrestore(&ha->vport_slock, flags);
|
||||
}
|
||||
set_bit(VP_DPC_NEEDED, &vha->dpc_flags);
|
||||
qla2xxx_wake_dpc(vha);
|
||||
@@ -4313,6 +4388,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 +4412,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 +4423,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 +4665,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 +4681,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 +4693,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 +4738,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 +4756,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 +4767,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 +5151,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 +5557,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 +5731,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 +5749,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 +5787,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 +5796,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 +5808,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;
|
||||
@@ -6490,23 +6579,21 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha,
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
dma_addr_t dd_dma;
|
||||
void *dd;
|
||||
|
||||
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,
|
||||
"Entered %s.\n", __func__);
|
||||
|
||||
dd_dma = dma_map_single(&vha->hw->pdev->dev,
|
||||
dd_buf, size, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(&vha->hw->pdev->dev, dd_dma)) {
|
||||
ql_log(ql_log_warn, vha, 0x1194, "Failed to map dma buffer.\n");
|
||||
dd = dma_alloc_coherent(&vha->hw->pdev->dev, size, &dd_dma, GFP_KERNEL);
|
||||
if (!dd) {
|
||||
ql_log(ql_log_warn, vha, 0x1194, "Failed to allocate dma buffer.\n");
|
||||
return QLA_MEMORY_ALLOC_FAILED;
|
||||
}
|
||||
|
||||
memset(dd_buf, 0, size);
|
||||
|
||||
mcp->mb[0] = MBC_DPORT_DIAGNOSTICS;
|
||||
mcp->mb[1] = options;
|
||||
mcp->mb[2] = MSW(LSD(dd_dma));
|
||||
@@ -6528,8 +6615,9 @@ qla26xx_dport_diagnostics(scsi_qla_host_t *vha,
|
||||
"Done %s.\n", __func__);
|
||||
}
|
||||
|
||||
dma_unmap_single(&vha->hw->pdev->dev, dd_dma,
|
||||
size, DMA_FROM_DEVICE);
|
||||
memcpy(dd_buf, dd, size);
|
||||
|
||||
dma_free_coherent(&vha->hw->pdev->dev, size, dd, dd_dma);
|
||||
|
||||
return rval;
|
||||
}
|
||||
@@ -7254,3 +7342,192 @@ int qla_mpipt_validate_fw(scsi_qla_host_t *vha, u16 img_idx, uint16_t *state)
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int qla29xx_flash_block_read(scsi_qla_host_t *vha, dma_addr_t req_dma,
|
||||
uint32_t flash_addr, uint32_t flash_size,
|
||||
uint16_t reg_code, uint16_t opt)
|
||||
{
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int rval = 0;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1067,
|
||||
"Entered %s options 0x%x.\n", __func__, opt);
|
||||
|
||||
memset(mcp->mb, 0, sizeof(mcp->mb));
|
||||
|
||||
if (!is_flash_read(opt)) {
|
||||
ql_log(ql_log_info, vha, 0x1068,
|
||||
"%s: Invalid flash option 0x%x.\n", __func__, opt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mcp->mb[0] = MBC_RD_WR_FLASH;
|
||||
|
||||
/* mailbox option field :
|
||||
* TIM img or Img : BIT_15 (1/0)
|
||||
* Last seg img : BIT_11 (1)
|
||||
* First seg img : BIT_10 (1)
|
||||
* dword or block : BIT_9 (1/0)
|
||||
* flash MBR update : BIT_8 (1/0)
|
||||
* Secure or non-secure : BIT_7 (1/0)
|
||||
* Write or Read : BIT_6 (1/0)
|
||||
* Last block img : BIT_5 (1)
|
||||
* First block img : BIT_4 (1)
|
||||
* Request type : (BIT3 - BIT_0)
|
||||
* - Normal
|
||||
* - Normal, Force Sema
|
||||
* - Initialize
|
||||
* - Initialize, Force sema
|
||||
* - Abort secured update
|
||||
*/
|
||||
mcp->mb[1] = opt;
|
||||
mcp->mb[2] = reg_code;
|
||||
|
||||
mcp->mb[3] = MSW(flash_size);
|
||||
mcp->mb[4] = LSW(flash_size);
|
||||
|
||||
mcp->mb[5] = MSW(req_dma);
|
||||
mcp->mb[6] = LSW(req_dma);
|
||||
mcp->mb[7] = MSW(MSD(req_dma));
|
||||
mcp->mb[8] = LSW(MSD(req_dma));
|
||||
|
||||
mcp->mb[9] = MSW(flash_addr);
|
||||
mcp->mb[10] = LSW(flash_addr);
|
||||
|
||||
mcp->out_mb =
|
||||
MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x103f,
|
||||
"Failed=%x mb=(0x%x,0x%x,0x%x,0x%x).\n",
|
||||
rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1043,
|
||||
"Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
|
||||
mcp->mb[0], mcp->mb[1], mcp->mb[2]);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int qla29xx_flash_block_write(scsi_qla_host_t *vha, dma_addr_t req_dma,
|
||||
uint32_t flash_addr, uint32_t flash_size,
|
||||
uint16_t reg_code, uint16_t opt)
|
||||
{
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int rval = 0;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1069,
|
||||
"Entered %s options 0x%x.\n", __func__, opt);
|
||||
|
||||
memset(mcp->mb, 0, sizeof(mcp->mb));
|
||||
|
||||
if (!is_flash_write(opt)) {
|
||||
ql_log(ql_log_info, vha, 0x106a,
|
||||
"%s: Invalid flash option 0x%x.\n", __func__, opt);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mcp->mb[0] = MBC_RD_WR_FLASH;
|
||||
|
||||
/* mailbox option field :
|
||||
* TIM img or Img : BIT_15 (1/0)
|
||||
* Last seg img : BIT_11 (1)
|
||||
* First seg img : BIT_10 (1)
|
||||
* dword or block : BIT_9 (1/0)
|
||||
* flash MBR update : BIT_8 (1/0)
|
||||
* Secure or non-secure : BIT_7 (1/0)
|
||||
* Write or Read : BIT_6 (1/0)
|
||||
* Last block img : BIT_5 (1)
|
||||
* First block img : BIT_4 (1)
|
||||
* Request type : (BIT3 - BIT_0)
|
||||
* - Normal
|
||||
* - Normal, Force Sema
|
||||
* - Initialize
|
||||
* - Initialize, Force sema
|
||||
* - Abort secured update
|
||||
*/
|
||||
mcp->mb[1] = opt;
|
||||
mcp->mb[2] = reg_code;
|
||||
|
||||
mcp->mb[3] = MSW(flash_size);
|
||||
mcp->mb[4] = LSW(flash_size);
|
||||
|
||||
mcp->mb[5] = MSW(req_dma);
|
||||
mcp->mb[6] = LSW(req_dma);
|
||||
mcp->mb[7] = MSW(MSD(req_dma));
|
||||
mcp->mb[8] = LSW(MSD(req_dma));
|
||||
|
||||
mcp->mb[9] = MSW(flash_addr);
|
||||
mcp->mb[10] = LSW(flash_addr);
|
||||
|
||||
mcp->out_mb =
|
||||
MBX_10|MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x110a,
|
||||
"Failed=%x mb=(0x%x,0x%x,0x%x,0x%x).\n",
|
||||
rval, mcp->mb[0], mcp->mb[1], mcp->mb[2], mcp->mb[3]);
|
||||
} else {
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110b,
|
||||
"Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
|
||||
mcp->mb[0], mcp->mb[1], mcp->mb[2]);
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
int
|
||||
qla29xx_load_dump_mpi(scsi_qla_host_t *vha, uint16_t opt, uint32_t mpi_addr,
|
||||
uint32_t dlen, dma_addr_t req_dma)
|
||||
{
|
||||
mbx_cmd_t mc;
|
||||
mbx_cmd_t *mcp = &mc;
|
||||
int rval = 0;
|
||||
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0xffff,
|
||||
"Entered %s mpi_addr 0x%x len 0x%x opt 0x%x.\n",
|
||||
__func__, mpi_addr, dlen, opt);
|
||||
|
||||
memset(mcp->mb, 0, sizeof(mcp->mb));
|
||||
|
||||
mcp->mb[0] = MBC_LOAD_DUMP_MPI_RAM;
|
||||
mcp->mb[9] = opt;
|
||||
mcp->mb[1] = LSW(mpi_addr);
|
||||
mcp->mb[8] = MSW(mpi_addr);
|
||||
|
||||
mcp->mb[2] = MSW(req_dma);
|
||||
mcp->mb[3] = LSW(req_dma);
|
||||
mcp->mb[6] = MSW(MSD(req_dma));
|
||||
mcp->mb[7] = LSW(MSD(req_dma));
|
||||
|
||||
mcp->mb[4] = MSW(dlen);
|
||||
mcp->mb[5] = LSW(dlen);
|
||||
|
||||
mcp->out_mb = MBX_9|MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
|
||||
mcp->in_mb = MBX_1|MBX_0;
|
||||
mcp->tov = MBX_TOV_SECONDS;
|
||||
mcp->flags = 0;
|
||||
|
||||
rval = qla2x00_mailbox_command(vha, mcp);
|
||||
if (rval != QLA_SUCCESS)
|
||||
ql_dbg(ql_dbg_mbx, vha, 0x110a,
|
||||
"Failed=%x mb=(0x%x,0x%x).\n",
|
||||
rval, mcp->mb[0], mcp->mb[1]);
|
||||
else
|
||||
ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x110b,
|
||||
"Done %s mb=(0x%x,0x%x,0x%x).\n", __func__,
|
||||
mcp->mb[0], mcp->mb[1], mcp->mb[2]);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
@@ -574,16 +574,19 @@ qla25xx_free_req_que(struct scsi_qla_host *vha, struct req_que *req)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint16_t que_id = req->id;
|
||||
size_t req_entry_size = qla_req_entry_size(ha);
|
||||
|
||||
dma_free_coherent(&ha->pdev->dev, (req->length + 1) *
|
||||
sizeof(request_t), req->ring, req->dma);
|
||||
if (req->ring)
|
||||
dma_free_coherent(&ha->pdev->dev,
|
||||
(req->length + 1) * req_entry_size,
|
||||
req->ring, req->dma);
|
||||
req->ring = NULL;
|
||||
req->dma = 0;
|
||||
if (que_id) {
|
||||
mutex_lock(&ha->mq_lock);
|
||||
ha->req_q_map[que_id] = NULL;
|
||||
mutex_lock(&ha->vport_lock);
|
||||
clear_bit(que_id, ha->req_qid_map);
|
||||
mutex_unlock(&ha->vport_lock);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
}
|
||||
kfree(req->outstanding_cmds);
|
||||
kfree(req);
|
||||
@@ -594,6 +597,7 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
uint16_t que_id = rsp->id;
|
||||
size_t rsp_entry_size = qla_rsp_entry_size(ha);
|
||||
|
||||
if (rsp->msix && rsp->msix->have_irq) {
|
||||
free_irq(rsp->msix->vector, rsp->msix->handle);
|
||||
@@ -601,15 +605,22 @@ 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);
|
||||
|
||||
/* Flush any queued response work before freeing the queue/qpair. */
|
||||
if (rsp->qpair && ha->wq)
|
||||
cancel_work_sync(&rsp->qpair->q_work);
|
||||
|
||||
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 +717,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 +728,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 +784,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 +800,15 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
|
||||
req->req_q_in = ®->isp25mq.req_q_in;
|
||||
req->req_q_out = ®->isp25mq.req_q_out;
|
||||
req->max_q_depth = ha->req_q_map[0]->max_q_depth;
|
||||
req->out_ptr = (uint16_t *)(req->ring + req->length);
|
||||
/*
|
||||
* out_ptr sits in the scratch slot immediately after the ring. Use
|
||||
* the 29xx-stride pointer when the ring is 128-byte-per-entry so the
|
||||
* pointer arithmetic resolves to the correct byte offset.
|
||||
*/
|
||||
if (IS_QLA29XX(ha))
|
||||
req->out_ptr = (uint16_t *)(req->ring_ext + req->length);
|
||||
else
|
||||
req->out_ptr = (uint16_t *)(req->ring + req->length);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
ql_dbg(ql_dbg_multiq, base_vha, 0xc004,
|
||||
"ring_ptr=%p ring_index=%d, "
|
||||
@@ -794,9 +826,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 +862,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 +873,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 +922,10 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
|
||||
reg = ISP_QUE_REG(ha, que_id);
|
||||
rsp->rsp_q_in = ®->isp25mq.rsp_q_in;
|
||||
rsp->rsp_q_out = ®->isp25mq.rsp_q_out;
|
||||
rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
|
||||
if (IS_QLA29XX(ha))
|
||||
rsp->in_ptr = (uint16_t *)(rsp->ring_ext + rsp->length);
|
||||
else
|
||||
rsp->in_ptr = (uint16_t *)(rsp->ring + rsp->length);
|
||||
mutex_unlock(&ha->mq_lock);
|
||||
ql_dbg(ql_dbg_multiq, base_vha, 0xc00b,
|
||||
"options=%x id=%d rsp_q_in=%p rsp_q_out=%p\n",
|
||||
@@ -908,9 +945,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 +991,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 > VP_CTRL_IDX_MAP_BITS)
|
||||
return QLA_PARAMETER_ERROR;
|
||||
|
||||
/* ref: INIT */
|
||||
sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL);
|
||||
if (!sp)
|
||||
|
||||
+226
-81
@@ -257,7 +257,9 @@ static void qla_nvme_release_lsrsp_cmd_kref(struct kref *kref)
|
||||
|
||||
fd_rsp = uctx->fd_rsp;
|
||||
|
||||
spin_lock_irqsave(&uctx->fcport->unsol_ctx_lock, flags);
|
||||
list_del(&uctx->elem);
|
||||
spin_unlock_irqrestore(&uctx->fcport->unsol_ctx_lock, flags);
|
||||
|
||||
fd_rsp->done(fd_rsp);
|
||||
kfree(uctx);
|
||||
@@ -374,6 +376,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 +443,14 @@ out:
|
||||
a.vp_idx = vha->vp_idx;
|
||||
a.nport_handle = uctx->nport_handle;
|
||||
a.xchg_address = uctx->exchange_address;
|
||||
qla_nvme_ls_reject_iocb(vha, ha->base_qpair, &a, true);
|
||||
if (ha->flags.fw_started) {
|
||||
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);
|
||||
}
|
||||
spin_lock_irqsave(&uctx->fcport->unsol_ctx_lock, flags);
|
||||
list_del(&uctx->elem);
|
||||
spin_unlock_irqrestore(&uctx->fcport->unsol_ctx_lock, flags);
|
||||
kfree(uctx);
|
||||
return rval;
|
||||
}
|
||||
@@ -463,8 +473,8 @@ 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);
|
||||
if (!schedule_work(&priv->abort_work))
|
||||
kref_put(&priv->sp->cmd_kref, priv->sp->put_fn);
|
||||
}
|
||||
|
||||
static int qla_nvme_ls_req(struct nvme_fc_local_port *lport,
|
||||
@@ -501,6 +511,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,8 +556,8 @@ 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);
|
||||
if (!schedule_work(&priv->abort_work))
|
||||
kref_put(&priv->sp->cmd_kref, priv->sp->put_fn);
|
||||
}
|
||||
|
||||
static inline int qla2x00_start_nvme_mq(srb_t *sp)
|
||||
@@ -554,7 +565,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 +596,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 +644,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 +724,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 +753,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 +809,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 +818,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 +888,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 +1079,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 +1161,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 +1209,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 +1315,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,8 +1328,17 @@ 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;
|
||||
qla_nvme_ls_reject_iocb(vha, vha->hw->base_qpair, &a, true);
|
||||
if (vha->hw->flags.fw_started) {
|
||||
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);
|
||||
}
|
||||
spin_lock_irqsave(&uctx->fcport->unsol_ctx_lock, flags);
|
||||
list_del(&uctx->elem);
|
||||
spin_unlock_irqrestore(&uctx->fcport->unsol_ctx_lock, flags);
|
||||
kfree(uctx);
|
||||
}
|
||||
}
|
||||
@@ -1238,6 +1380,7 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp)
|
||||
struct purex_item *item;
|
||||
port_id_t d_id = {0};
|
||||
port_id_t id = {0};
|
||||
unsigned long flags;
|
||||
u8 *opcode;
|
||||
bool xmt_reject = false;
|
||||
|
||||
@@ -1303,7 +1446,9 @@ void qla2xxx_process_purls_iocb(void **pkt, struct rsp_que **rsp)
|
||||
uctx->ox_id = p->ox_id;
|
||||
qla_rport->uctx = uctx;
|
||||
INIT_LIST_HEAD(&uctx->elem);
|
||||
spin_lock_irqsave(&fcport->unsol_ctx_lock, flags);
|
||||
list_add_tail(&uctx->elem, &fcport->unsol_ctx_head);
|
||||
spin_unlock_irqrestore(&fcport->unsol_ctx_lock, flags);
|
||||
item->purls_context = (void *)uctx;
|
||||
|
||||
ql_dbg(ql_dbg_unsol, vha, 0x2121,
|
||||
|
||||
@@ -144,7 +144,7 @@ struct pt_ls4_rx_unsol {
|
||||
int qla_nvme_register_hba(struct scsi_qla_host *);
|
||||
int qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *);
|
||||
void qla_nvme_delete(struct scsi_qla_host *);
|
||||
void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *, struct pt_ls4_request *,
|
||||
struct req_que *);
|
||||
void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha, void *pkt,
|
||||
struct req_que *req);
|
||||
void qla24xx_async_gffid_sp_done(struct srb *sp, int);
|
||||
#endif
|
||||
|
||||
@@ -2663,7 +2663,7 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, __le32 *dwptr,
|
||||
|
||||
ret = qla2x00_load_ram(vha, optrom_dma,
|
||||
(ha->flash_data_off | faddr),
|
||||
OPTROM_BURST_DWORDS);
|
||||
OPTROM_BURST_DWORDS, 0);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0xb01e,
|
||||
"Unable to burst-write optrom segment "
|
||||
|
||||
+264
-52
@@ -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 @@ fail_req_map:
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -2127,7 +2132,7 @@ skip_pio:
|
||||
ha->msix_count = msix + 1;
|
||||
/* Max queues are bounded by available msix vectors */
|
||||
/* MB interrupt uses 1 vector */
|
||||
ha->max_req_queues = ha->msix_count - 1;
|
||||
ha->max_req_queues = qla_calc_queue_count(ha->msix_count);
|
||||
ha->max_rsp_queues = ha->max_req_queues;
|
||||
/* Queue pairs is the max value minus the base queue pair */
|
||||
ha->max_qpairs = ha->max_rsp_queues - 1;
|
||||
@@ -2153,8 +2158,6 @@ iospace_error_exit:
|
||||
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,20 +2206,28 @@ 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)
|
||||
*/
|
||||
if (ql2xmqsupport || ql2xnvmeenable) {
|
||||
/* MB interrupt uses 1 vector */
|
||||
ha->max_req_queues = ha->msix_count - 1;
|
||||
ha->max_req_queues = qla_calc_queue_count(ha->msix_count);
|
||||
|
||||
/* ATIOQ needs 1 vector. That's 1 less QPair */
|
||||
if (QLA_TGT_MODE_ENABLED())
|
||||
if (QLA_TGT_MODE_ENABLED() && ha->max_req_queues > 1)
|
||||
ha->max_req_queues--;
|
||||
|
||||
ha->max_rsp_queues = ha->max_req_queues;
|
||||
@@ -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))
|
||||
@@ -2803,11 +2888,15 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha)
|
||||
else {
|
||||
/* Get adapter physical port no from interrupt pin register. */
|
||||
pci_read_config_byte(ha->pdev, PCI_INTERRUPT_PIN, &ha->port_no);
|
||||
if (IS_QLA25XX(ha) || IS_QLA2031(ha) ||
|
||||
IS_QLA27XX(ha) || IS_QLA28XX(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
|
||||
} else {
|
||||
ha->port_no = !(ha->port_no & 1);
|
||||
}
|
||||
}
|
||||
|
||||
ql_dbg_pci(ql_dbg_init, ha->pdev, 0x000b,
|
||||
@@ -2936,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,
|
||||
@@ -2998,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;
|
||||
@@ -3195,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,
|
||||
@@ -3373,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;
|
||||
@@ -3614,6 +3725,14 @@ skip_dpc:
|
||||
if (test_bit(UNLOADING, &base_vha->dpc_flags))
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* FW dump can happens before sysfs nodes are created. If sysfs nodes
|
||||
* are unavailable then udev script will not be able to read the fw dump.
|
||||
* Notify udev to read again, now that sysfs nodes are available.
|
||||
*/
|
||||
if (ha->fw_dumped || ha->mpi_fw_dumped)
|
||||
qla2x00_post_uevent_work(base_vha, QLA_UEVENT_CODE_FW_DUMP);
|
||||
|
||||
return 0;
|
||||
|
||||
probe_failed:
|
||||
@@ -3733,7 +3852,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 {
|
||||
@@ -3898,7 +4017,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)) {
|
||||
@@ -3933,8 +4052,6 @@ qla2x00_remove_one(struct pci_dev *pdev)
|
||||
|
||||
qla2x00_dfs_remove(base_vha);
|
||||
|
||||
qla84xx_put_chip(base_vha);
|
||||
|
||||
/* Disable timer */
|
||||
if (base_vha->timer_active)
|
||||
qla2x00_stop_timer(base_vha);
|
||||
@@ -3959,6 +4076,8 @@ qla2x00_remove_one(struct pci_dev *pdev)
|
||||
|
||||
scsi_remove_host(base_vha->host);
|
||||
|
||||
qla84xx_put_chip(base_vha);
|
||||
|
||||
qla2x00_free_device(base_vha);
|
||||
|
||||
qla2x00_clear_drv_active(ha);
|
||||
@@ -4147,6 +4266,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,
|
||||
@@ -4176,7 +4297,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",
|
||||
@@ -4210,7 +4332,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) {
|
||||
@@ -4342,13 +4465,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) {
|
||||
@@ -4359,13 +4486,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,
|
||||
@@ -4387,7 +4518,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)
|
||||
@@ -4397,7 +4528,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)
|
||||
@@ -4446,6 +4577,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);
|
||||
@@ -4453,7 +4592,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;
|
||||
@@ -4484,36 +4623,56 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len,
|
||||
fail_lsrjt:
|
||||
dma_free_coherent(&ha->pdev->dev, ha->elsrej.size,
|
||||
ha->elsrej.c, ha->elsrej.cdma);
|
||||
ha->elsrej.c = NULL;
|
||||
ha->elsrej.cdma = 0;
|
||||
fail_elsrej:
|
||||
dma_pool_destroy(ha->purex_dma_pool);
|
||||
ha->purex_dma_pool = NULL;
|
||||
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);
|
||||
ha->flt = NULL;
|
||||
ha->flt_dma = 0;
|
||||
|
||||
fail_flt_buffer:
|
||||
dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE,
|
||||
ha->sfp_data, ha->sfp_data_dma);
|
||||
ha->sfp_data = NULL;
|
||||
ha->sfp_data_dma = 0;
|
||||
fail_sfp_data:
|
||||
kfree(ha->loop_id_map);
|
||||
ha->loop_id_map = NULL;
|
||||
fail_loop_id_map:
|
||||
dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma);
|
||||
ha->async_pd = NULL;
|
||||
ha->async_pd_dma = 0;
|
||||
fail_async_pd:
|
||||
dma_pool_free(ha->s_dma_pool, ha->sf_init_cb, ha->sf_init_cb_dma);
|
||||
ha->sf_init_cb = NULL;
|
||||
ha->sf_init_cb_dma = 0;
|
||||
fail_sf_init_cb:
|
||||
dma_pool_free(ha->s_dma_pool, ha->ex_init_cb, ha->ex_init_cb_dma);
|
||||
ha->ex_init_cb = NULL;
|
||||
ha->ex_init_cb_dma = 0;
|
||||
fail_ex_init_cb:
|
||||
kfree(ha->npiv_info);
|
||||
ha->npiv_info = NULL;
|
||||
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:
|
||||
@@ -4551,12 +4710,12 @@ fail_dma_pool:
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -4566,6 +4725,7 @@ fail_s_dma_pool:
|
||||
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;
|
||||
@@ -4921,6 +5081,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;
|
||||
@@ -5027,6 +5191,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);
|
||||
@@ -6000,13 +6165,15 @@ retry_lock:
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -6071,15 +6238,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 =
|
||||
@@ -6089,13 +6269,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);
|
||||
@@ -6119,12 +6305,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];
|
||||
@@ -6424,13 +6610,13 @@ send:
|
||||
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,
|
||||
@@ -6454,9 +6640,9 @@ dealloc:
|
||||
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
|
||||
@@ -6828,8 +7014,6 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
|
||||
|
||||
qla2x00_dfs_remove(base_vha);
|
||||
|
||||
qla84xx_put_chip(base_vha);
|
||||
|
||||
if (base_vha->timer_active)
|
||||
qla2x00_stop_timer(base_vha);
|
||||
|
||||
@@ -6847,6 +7031,8 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work)
|
||||
|
||||
scsi_remove_host(base_vha->host);
|
||||
|
||||
qla84xx_put_chip(base_vha);
|
||||
|
||||
base_vha->flags.init_done = 0;
|
||||
qla25xx_delete_queues(base_vha);
|
||||
qla2x00_free_fcports(base_vha);
|
||||
@@ -7616,6 +7802,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"
|
||||
@@ -7629,6 +7816,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);
|
||||
@@ -7646,6 +7834,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, },
|
||||
};
|
||||
|
||||
@@ -7679,6 +7868,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;
|
||||
}
|
||||
@@ -8155,6 +8346,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);
|
||||
@@ -8190,17 +8385,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);
|
||||
@@ -8214,20 +8413,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);
|
||||
@@ -8251,17 +8456,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);
|
||||
@@ -8381,3 +8592,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);
|
||||
|
||||
+769
-13
@@ -10,6 +10,655 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
/**
|
||||
* qla29xx_get_flt_layout - Retrieve the flash layout table (FLT) for QLA29xx.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
*
|
||||
* This function reads and validates the FLT structure from the flash memory.
|
||||
* It extracts region information and updates the hardware data structure.
|
||||
*/
|
||||
static void
|
||||
qla29xx_get_flt_layout(scsi_qla_host_t *vha)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flash_layout *flt_layout = ha->flt_data;
|
||||
struct qla_flt_region_header *flt_header = &flt_layout->flt_header;
|
||||
struct qla_flt_region_data *region = &flt_layout->region[0];
|
||||
uint32_t flt_options = 0;
|
||||
uint32_t flt_size;
|
||||
uint32_t cnt, chksum;
|
||||
uint16_t reg_cnt, i;
|
||||
__le32 *wptr;
|
||||
void *buf = NULL;
|
||||
|
||||
flt_size = sizeof(struct qla_flt_region_header);
|
||||
wptr = (__force __le32 *)ha->flt_data;
|
||||
|
||||
buf = qla29xx_read_optrom_data(vha, FLT_REG_MINI_FLT, flt_options,
|
||||
ha->flt_data, 0, flt_size);
|
||||
if (!buf) {
|
||||
ql_log(ql_log_warn, vha, 0x007b,
|
||||
"Failed to read FLT information.\n");
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x0111,
|
||||
"Contents of Flash Layout (0x%x):\n", flt_size);
|
||||
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0112,
|
||||
ha->flt_data, flt_size);
|
||||
|
||||
/* check flt version checksum and other info */
|
||||
if ((le32_to_cpu(*wptr) == 0xffffffff) ||
|
||||
flt_header->version != cpu_to_le32(FLT_HDR_VERSION)) {
|
||||
ql_log(ql_log_warn, vha, 0x007c,
|
||||
"Unsupported FLT detected: version=0x%x length=0x%x signature=0x%x region_count=0x%x checksum=0x%x.\n",
|
||||
le32_to_cpu(flt_header->version),
|
||||
le32_to_cpu(flt_header->length),
|
||||
le32_to_cpu(flt_header->signature),
|
||||
le16_to_cpu(flt_header->region_count),
|
||||
le32_to_cpu(flt_header->checksum));
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
reg_cnt = le16_to_cpu(flt_header->region_count);
|
||||
if (reg_cnt > FLT_MAX_REGIONS)
|
||||
goto exit_flt;
|
||||
|
||||
if (le16_to_cpu(flt_header->region_size) !=
|
||||
sizeof(struct qla_flt_region_data)) {
|
||||
ql_log(ql_log_warn, vha, 0x0082,
|
||||
"Unsupported FLT region size 0x%x (expected 0x%zx).\n",
|
||||
le16_to_cpu(flt_header->region_size),
|
||||
sizeof(struct qla_flt_region_data));
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
flt_size = sizeof(struct qla_flash_layout) +
|
||||
(reg_cnt * le16_to_cpu(flt_header->region_size));
|
||||
if (flt_size > sizeof(struct qla_flash_layout) +
|
||||
sizeof(struct qla_flt_region_data) * FLT_DATA_MAX_REGIONS) {
|
||||
ql_log(ql_log_warn, vha, 0x007d,
|
||||
"FLT size 0x%x exceeds buffer, region_size=0x%x.\n",
|
||||
flt_size, le16_to_cpu(flt_header->region_size));
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
buf = qla29xx_read_optrom_data(vha, FLT_REG_MINI_FLT, flt_options,
|
||||
ha->flt_data, 0, flt_size);
|
||||
if (!buf) {
|
||||
ql_log(ql_log_warn, vha, 0x007b,
|
||||
"Failed to read FLT information.\n");
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
cnt = le32_to_cpu(flt_header->length) / sizeof(*wptr);
|
||||
if (cnt > flt_size / sizeof(*wptr)) {
|
||||
ql_log(ql_log_warn, vha, 0x007e,
|
||||
"FLT length 0x%x exceeds read size 0x%x, rejecting.\n",
|
||||
le32_to_cpu(flt_header->length), flt_size);
|
||||
goto exit_flt;
|
||||
}
|
||||
for (chksum = 0; cnt--; wptr++)
|
||||
chksum += le32_to_cpu(*wptr);
|
||||
if (chksum) {
|
||||
ql_log(ql_log_fatal, vha, 0x007f,
|
||||
"Inconsistent FLT detected: version=0x%x length=0x%x signature=0x%x checksum=0x%x.\n",
|
||||
le32_to_cpu(flt_header->version),
|
||||
le32_to_cpu(flt_header->length),
|
||||
le32_to_cpu(flt_header->signature),
|
||||
le32_to_cpu(flt_header->checksum));
|
||||
goto exit_flt;
|
||||
}
|
||||
|
||||
ql_dbg(ql_dbg_init, vha, 0x007f,
|
||||
"FLT detected: version=0x%08x length=0x%08x signature=0x%08x region_count=0x%04x region_len=0x%04x segment_len=0x%08x checksum=0x%08x.\n",
|
||||
le32_to_cpu(flt_header->version),
|
||||
le32_to_cpu(flt_header->length),
|
||||
le32_to_cpu(flt_header->signature),
|
||||
le16_to_cpu(flt_header->region_count),
|
||||
le16_to_cpu(flt_header->region_size),
|
||||
le32_to_cpu(flt_header->segment_size),
|
||||
le32_to_cpu(flt_header->checksum));
|
||||
|
||||
for (i = 0; reg_cnt; i++, reg_cnt--) {
|
||||
region = &flt_layout->region[i];
|
||||
ql_dbg(ql_dbg_init, vha, 0x0080,
|
||||
"FLT[%03x]: len=0x%08x version=0x%08x attr=0x%02x.\n",
|
||||
le16_to_cpu(region->region_code),
|
||||
le32_to_cpu(region->image_length),
|
||||
le32_to_cpu(region->version),
|
||||
le32_to_cpu(region->attribute));
|
||||
if (le16_to_cpu(region->region_code) == FLT_REG_FW_DUMP_TMPLT) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x0080,
|
||||
"%s: %d: Found FW dump template", __func__, __LINE__);
|
||||
ha->fw_dump_tmplt_len = le32_to_cpu(region->image_length);
|
||||
}
|
||||
}
|
||||
|
||||
if (le32_to_cpu(flt_header->segment_size) >= sizeof(uint32_t)) {
|
||||
ha->flt_segment_length = le32_to_cpu(flt_header->segment_size);
|
||||
} else {
|
||||
ql_log(ql_log_warn, vha, 0x0081,
|
||||
"FLT segment size 0x%x too small, using default 0x%x.\n",
|
||||
le32_to_cpu(flt_header->segment_size), QLA_SEGMENT_LENGTH);
|
||||
ha->flt_segment_length = QLA_SEGMENT_LENGTH;
|
||||
}
|
||||
ha->flags.valid_flt = true;
|
||||
return;
|
||||
|
||||
exit_flt:
|
||||
ha->flt_segment_length = QLA_SEGMENT_LENGTH;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_get_fdt_info - Retrieve flash descriptor table (FDT) information.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
*
|
||||
* This function reads and validates the FDT structure from the flash memory.
|
||||
* It extracts manufacturer and device-specific information and updates
|
||||
* the hardware data structure.
|
||||
*/
|
||||
static void
|
||||
qla29xx_get_fdt_info(scsi_qla_host_t *vha)
|
||||
{
|
||||
#define FLASH_BLK_SIZE_4K 0x1000
|
||||
#define FLASH_BLK_SIZE_32K 0x8000
|
||||
#define FLASH_BLK_SIZE_64K 0x10000
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct req_que *req = ha->req_q_map[0];
|
||||
uint16_t cnt, chksum;
|
||||
__le16 *wptr = (__force __le16 *)req->ring;
|
||||
struct qla_fdt_layout *fdt = (struct qla_fdt_layout *)req->ring;
|
||||
uint32_t fdt_options = 0;
|
||||
void *buf = NULL;
|
||||
|
||||
buf = qla29xx_read_optrom_data(vha, FLT_REG_FDT, fdt_options,
|
||||
fdt, 0, sizeof(*fdt));
|
||||
if (!buf) {
|
||||
ql_log(ql_log_warn, vha, 0x0047,
|
||||
"Failed to read FLT information.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (le16_to_cpu(*wptr) == 0xffff)
|
||||
return;
|
||||
if (memcmp(fdt->sig, "QLID", 4))
|
||||
return;
|
||||
|
||||
for (cnt = 0, chksum = 0; cnt < sizeof(*fdt) >> 1; cnt++, wptr++)
|
||||
chksum += le16_to_cpu(*wptr);
|
||||
if (chksum) {
|
||||
ql_dbg(ql_dbg_init, vha, 0x004c,
|
||||
"Inconsistent FDT detected: checksum=0x%x id=%c version0x%x.\n",
|
||||
chksum, fdt->sig[0], le16_to_cpu(fdt->version));
|
||||
ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113,
|
||||
fdt, sizeof(*fdt));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_get_flash_region - Retrieve flash region information for QLA29xx adapters.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
* @code: Region code to identify the flash region.
|
||||
* @region: Pointer to store the retrieved flash region information.
|
||||
*
|
||||
* This function retrieves the flash region information for QLA29xx adapters
|
||||
* based on the specified region code.
|
||||
*
|
||||
* Returns QLA_SUCCESS on success or QLA_FUNCTION_FAILED on failure.
|
||||
*/
|
||||
static int
|
||||
qla29xx_get_flash_region(struct scsi_qla_host *vha, uint32_t code,
|
||||
struct qla_flt_region_data *region)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flash_layout *flt = ha->flt_data;
|
||||
struct qla_flt_region_header *flt_hdr = &flt->flt_header;
|
||||
struct qla_flt_region_data *flt_reg = &flt->region[0];
|
||||
uint16_t cnt;
|
||||
int rval = QLA_FUNCTION_FAILED;
|
||||
|
||||
if (!ha->flt_data || !ha->flags.valid_flt)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
|
||||
cnt = le16_to_cpu(flt_hdr->region_count);
|
||||
if (cnt > FLT_MAX_REGIONS)
|
||||
return QLA_FUNCTION_FAILED;
|
||||
/*
|
||||
* flt_reg++ strides by sizeof(struct qla_flt_region_data). This is
|
||||
* safe because valid_flt is set only after qla29xx_get_flt_layout()
|
||||
* has verified the firmware region_size equals that struct size.
|
||||
*/
|
||||
for (; cnt; cnt--, flt_reg++) {
|
||||
if (le16_to_cpu(flt_reg->region_code) == code) {
|
||||
memcpy((uint8_t *)region, flt_reg,
|
||||
sizeof(struct qla_flt_region_data));
|
||||
rval = QLA_SUCCESS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* set_segment_bits - Set segment-related bits in the options field.
|
||||
* @options: Pointer to the options field.
|
||||
* @segment_index: Index of the current segment.
|
||||
* @total: Total number of segments.
|
||||
*
|
||||
* This function sets the appropriate bits in the options field to indicate
|
||||
* whether the current segment is the first, last, or a single segment.
|
||||
*/
|
||||
static void set_segment_bits(uint16_t *options, int segment_index, int total)
|
||||
{
|
||||
/* - Single segment complete image.
|
||||
* - 1st Segment of an image.
|
||||
* - Last segment of an image.
|
||||
*/
|
||||
if (total == 1)
|
||||
*options |= (1 << 10) | (1 << 11);
|
||||
else if (segment_index == 0)
|
||||
*options |= (1 << 10);
|
||||
else if (segment_index == total - 1)
|
||||
*options |= (1 << 11);
|
||||
}
|
||||
|
||||
/**
|
||||
* set_chunk_bits - Set chunk-related bits in the options field.
|
||||
* @options: Pointer to the options field.
|
||||
* @count: Index of the current chunk.
|
||||
* @total: Total number of chunks.
|
||||
*
|
||||
* This function sets the appropriate bits in the options field to indicate
|
||||
* whether the current chunk is the first, last, or a single chunk.
|
||||
*/
|
||||
static void set_chunk_bits(uint16_t *options, int count, int total)
|
||||
{
|
||||
/* - Single chunk complete segment
|
||||
* - 1st chunk of a segment
|
||||
* - Last chunk of a segment
|
||||
*/
|
||||
if (total == 1)
|
||||
*options |= (1 << 4) | (1 << 5);
|
||||
else if (count == 0)
|
||||
*options |= (1 << 4);
|
||||
else if (count == total - 1)
|
||||
*options |= (1 << 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_write_optrom_data - Write data to the optrom for QLA29xx adapters.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
* @reg_code: Region code to write to.
|
||||
* @opts: Options for the write operation.
|
||||
* @buf: Buffer containing the data to write.
|
||||
* @offset: Offset within the region to start writing.
|
||||
* @length: Length of data to write.
|
||||
*
|
||||
* This function writes data to the specified optrom region for QLA29xx adapters.
|
||||
*
|
||||
* Returns 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int
|
||||
qla29xx_write_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
|
||||
uint16_t opts, void *buf, uint32_t offset,
|
||||
uint32_t length)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flt_region_data region;
|
||||
dma_addr_t optrom_dma;
|
||||
uint32_t faddr, left, burst;
|
||||
uint32_t img_len, seg_dlen;
|
||||
uint32_t region_len, region_dlen;
|
||||
void *optrom;
|
||||
uint8_t *pbuf;
|
||||
int rval = -EINVAL;
|
||||
uint16_t total_segments, segment_index = 0;
|
||||
uint16_t chunk_index = 0;
|
||||
|
||||
memset(®ion, 0, sizeof(region));
|
||||
|
||||
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
|
||||
&optrom_dma, GFP_KERNEL);
|
||||
if (!optrom) {
|
||||
ql_log(ql_log_warn, vha, 0x0090,
|
||||
"Unable to allocate memory for optrom burst read (%x KB).\n",
|
||||
OPTROM_BURST_SIZE / 1024);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (ha->flags.valid_flt && length == 0) {
|
||||
/* Get image length and segment length from FLT */
|
||||
rval = qla29xx_get_flash_region(vha, reg_code, ®ion);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x0092,
|
||||
"Invalid address %x - not a region start address\n",
|
||||
reg_code);
|
||||
goto free_buf;
|
||||
}
|
||||
img_len = le32_to_cpu(region.image_length);
|
||||
} else {
|
||||
img_len = length;
|
||||
}
|
||||
|
||||
seg_dlen = ha->flt_segment_length >> 2;
|
||||
region_len = (length > 0) ? length : img_len;
|
||||
region_dlen = (region_len >> 2);
|
||||
total_segments = (region_dlen + seg_dlen - 1) / seg_dlen;
|
||||
|
||||
faddr = offset >> 2;
|
||||
left = region_dlen;
|
||||
burst = OPTROM_BURST_DWORDS;
|
||||
pbuf = buf;
|
||||
|
||||
while (region_dlen > 0) {
|
||||
uint32_t segment_size, total_chunks;
|
||||
uint16_t options = 0;
|
||||
|
||||
segment_size = (region_dlen > seg_dlen) ? seg_dlen : region_dlen;
|
||||
total_chunks = (segment_size + OPTROM_BURST_DWORDS - 1) /
|
||||
OPTROM_BURST_DWORDS;
|
||||
|
||||
burst = OPTROM_BURST_DWORDS;
|
||||
if (burst > left)
|
||||
burst = left;
|
||||
if (burst > segment_size - chunk_index * OPTROM_BURST_DWORDS)
|
||||
burst = segment_size - chunk_index * OPTROM_BURST_DWORDS;
|
||||
|
||||
set_segment_bits(&options, segment_index, total_segments);
|
||||
set_chunk_bits(&options, chunk_index, total_chunks);
|
||||
|
||||
/* flash block write operations */
|
||||
SET_FW_BIT(options, BIT_6);
|
||||
CLEAR_FW_BIT(options, BIT_9);
|
||||
|
||||
check_and_set_mbc_bits(opts, options, BIT_15, BIT_15);
|
||||
check_and_set_mbc_bits(opts, options, BIT_7, BIT_7);
|
||||
|
||||
if (segment_index == total_segments - 1 &&
|
||||
chunk_index == total_chunks - 1)
|
||||
check_and_set_mbc_bits(opts, options, BIT_8, BIT_8);
|
||||
|
||||
memcpy(optrom, pbuf, burst * 4);
|
||||
|
||||
/* faddr is offset relative to region code */
|
||||
rval = qla29xx_flash_block_write(vha, optrom_dma,
|
||||
faddr, burst, reg_code, options);
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x0095,
|
||||
"Unable to burst-write optrom segment (%x/%x/%llx).\n",
|
||||
rval, faddr, (unsigned long long)optrom_dma);
|
||||
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
|
||||
optrom, optrom_dma);
|
||||
goto exit_write;
|
||||
}
|
||||
|
||||
left -= burst;
|
||||
faddr += burst;
|
||||
pbuf += burst * 4;
|
||||
chunk_index++;
|
||||
if (chunk_index >= total_chunks) {
|
||||
chunk_index = 0;
|
||||
segment_index++;
|
||||
region_dlen -= segment_size;
|
||||
}
|
||||
}
|
||||
|
||||
free_buf:
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
|
||||
optrom_dma);
|
||||
return rval;
|
||||
|
||||
exit_write:
|
||||
return rval;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_read_optrom_data - Read data from the optrom for QLA29xx adapters.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
* @reg_code: Region code to read from.
|
||||
* @opts: Options for the read operation.
|
||||
* @buf: Buffer to store the read data.
|
||||
* @offset: Offset within the region to start reading.
|
||||
* @length: Length of data to read.
|
||||
*
|
||||
* This function reads data from the specified optrom region for QLA29xx adapters.
|
||||
*
|
||||
* Returns a pointer to the buffer on success or NULL on failure.
|
||||
*/
|
||||
void *
|
||||
qla29xx_read_optrom_data(struct scsi_qla_host *vha, uint16_t reg_code,
|
||||
uint16_t opts, void *buf, uint32_t offset,
|
||||
uint32_t length)
|
||||
{
|
||||
struct qla_hw_data *ha = vha->hw;
|
||||
struct qla_flt_region_data region;
|
||||
dma_addr_t optrom_dma;
|
||||
uint32_t faddr, left, burst;
|
||||
uint32_t img_len, seg_dlen;
|
||||
uint32_t region_len, region_dlen;
|
||||
void *optrom;
|
||||
uint8_t *pbuf;
|
||||
uint16_t total_segments, segment_index = 0;
|
||||
uint16_t chunk_index = 0;
|
||||
int rval;
|
||||
|
||||
memset(®ion, 0, sizeof(region));
|
||||
|
||||
optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
|
||||
&optrom_dma, GFP_KERNEL);
|
||||
if (!optrom) {
|
||||
ql_log(ql_log_warn, vha, 0x0093,
|
||||
"Unable to allocate memory for optrom burst read (%x KB).\n",
|
||||
OPTROM_BURST_SIZE / 1024);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ha->flags.valid_flt && length == 0) {
|
||||
/* Get image length and segment length from FLT */
|
||||
rval = qla29xx_get_flash_region(vha, reg_code, ®ion);
|
||||
if (rval != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x7033,
|
||||
"Invalid address %x - not a region start address\n",
|
||||
reg_code);
|
||||
goto free_buf;
|
||||
}
|
||||
img_len = le32_to_cpu(region.image_length);
|
||||
} else {
|
||||
img_len = length;
|
||||
}
|
||||
|
||||
seg_dlen = ha->flt_segment_length >> 2;
|
||||
region_len = (length > 0) ? length : img_len;
|
||||
region_dlen = (region_len >> 2);
|
||||
total_segments = (region_dlen + seg_dlen - 1) / seg_dlen;
|
||||
|
||||
faddr = offset >> 2;
|
||||
left = region_dlen;
|
||||
burst = OPTROM_BURST_DWORDS;
|
||||
pbuf = buf;
|
||||
|
||||
ql_log(ql_log_info, vha, 0x0096,
|
||||
"Reg[0x%x]: options=0x%x length=0x%x offset=0x%x segments=%u\n",
|
||||
reg_code, opts, region_len, offset, total_segments);
|
||||
|
||||
while (region_dlen > 0) {
|
||||
uint32_t segment_size, total_chunks;
|
||||
uint16_t options = 0;
|
||||
|
||||
segment_size = (region_dlen > seg_dlen) ? seg_dlen : region_dlen;
|
||||
total_chunks = (segment_size + OPTROM_BURST_DWORDS - 1) /
|
||||
OPTROM_BURST_DWORDS;
|
||||
|
||||
burst = OPTROM_BURST_DWORDS;
|
||||
if (burst > left)
|
||||
burst = left;
|
||||
if (burst > segment_size - chunk_index * OPTROM_BURST_DWORDS)
|
||||
burst = segment_size - chunk_index * OPTROM_BURST_DWORDS;
|
||||
|
||||
set_segment_bits(&options, segment_index, total_segments);
|
||||
set_chunk_bits(&options, chunk_index, total_chunks);
|
||||
|
||||
/* flash block read operations */
|
||||
CLEAR_FW_BIT(options, BIT_9);
|
||||
CLEAR_FW_BIT(options, BIT_6);
|
||||
|
||||
options |= opts;
|
||||
|
||||
/* faddr is offset relative to region code */
|
||||
rval = qla29xx_flash_block_read(vha, optrom_dma,
|
||||
faddr, burst, reg_code, options);
|
||||
if (rval) {
|
||||
ql_log(ql_log_warn, vha, 0x0097,
|
||||
"Unable to burst-read optrom segment (%x/%x/%llx).\n",
|
||||
rval, faddr, (unsigned long long)optrom_dma);
|
||||
goto free_buf;
|
||||
}
|
||||
|
||||
memcpy(pbuf, optrom, burst * 4);
|
||||
|
||||
left -= burst;
|
||||
faddr += burst;
|
||||
pbuf += burst * 4;
|
||||
chunk_index++;
|
||||
if (chunk_index >= total_chunks) {
|
||||
chunk_index = 0;
|
||||
segment_index++;
|
||||
region_dlen -= segment_size;
|
||||
}
|
||||
}
|
||||
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
|
||||
optrom_dma);
|
||||
return buf;
|
||||
|
||||
free_buf:
|
||||
dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
|
||||
optrom_dma);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void set_chunk_mpi_bits(uint16_t *options, int count, int total)
|
||||
{
|
||||
/* - Single chunk complete segment/image
|
||||
* - 1st chunk of a segment/image
|
||||
* - Last chunk of a segment/image
|
||||
*/
|
||||
if (total == 1)
|
||||
*options |= BIT_2 | BIT_1;
|
||||
else if (count == 0)
|
||||
*options |= BIT_1;
|
||||
else if (count == total - 1)
|
||||
*options |= BIT_2;
|
||||
}
|
||||
|
||||
/**
|
||||
* qla29xx_mpi_optrom_data - Dump/load MPI optrom data for 29xx.
|
||||
* @vha: Pointer to SCSI QLogic host structure.
|
||||
* @opts: Options for the operation.
|
||||
* @buf: Buffer to read from/write to.
|
||||
* @offset: MPI RAM address, in 32-bit words (MBC_LOAD_DUMP_MPI_RAM is
|
||||
* word-addressed; not a byte offset).
|
||||
* @length: Length of data, in bytes (converted internally to a word count).
|
||||
* @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 +1766,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 +1789,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 +2031,7 @@ next:
|
||||
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 +3631,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 +4105,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 +4209,31 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
|
||||
memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
|
||||
|
||||
/* ISP29xx: get FW version from FLT region metadata */
|
||||
if (IS_QLA29XX(ha)) {
|
||||
struct qla_flt_region_data region;
|
||||
|
||||
ret = qla29xx_get_flash_region(vha, FLT_REG_FW, ®ion);
|
||||
if (ret != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0x7033,
|
||||
"Invalid region %x\n", FLT_REG_FW);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ha->fw_revision[0] = (le32_to_cpu(region.version) >> 16) & 0xff;
|
||||
ha->fw_revision[1] = (le32_to_cpu(region.version) >> 8) & 0xff;
|
||||
ha->fw_revision[2] = le32_to_cpu(region.version) & 0xff;
|
||||
|
||||
/* BIOS/FCODE/EFI version from the boot-code region. */
|
||||
qla29xx_get_boot_version(vha, mbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pcihdr = ha->flt_region_boot << 2;
|
||||
if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
|
||||
qla27xx_get_active_image(vha, &active_regions);
|
||||
if (active_regions.global == QLA27XX_SECONDARY_IMAGE) {
|
||||
if (active_regions.global == QLA27XX_SECONDARY_IMAGE)
|
||||
pcihdr = ha->flt_region_boot_sec << 2;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
@@ -3486,7 +4242,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 +4250,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 +4260,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 +4271,7 @@ qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
|
||||
ql_log(ql_log_fatal, vha, 0x005a,
|
||||
"PCI data struct not found pcir_adr=%x.\n", pcids);
|
||||
ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32);
|
||||
return QLA_FUNCTION_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read version */
|
||||
|
||||
@@ -1738,8 +1738,8 @@ static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd)
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr;
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp = (struct abts_resp_to_24xx *)qla_req_ring_slot(ha, qpair->req);
|
||||
memset(resp, 0, qla_req_entry_size(ha));
|
||||
|
||||
h = qlt_make_handle(qpair);
|
||||
if (unlikely(h == QLA_TGT_NULL_HANDLE)) {
|
||||
@@ -2490,17 +2490,13 @@ static int qlt_check_reserve_free_req(struct qla_qpair *qpair,
|
||||
/*
|
||||
* ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire
|
||||
*/
|
||||
static inline void *qlt_get_req_pkt(struct req_que *req)
|
||||
static inline void *qlt_get_req_pkt(struct qla_hw_data *ha,
|
||||
struct req_que *req)
|
||||
{
|
||||
/* Adjust ring index. */
|
||||
req->ring_index++;
|
||||
if (req->ring_index == req->length) {
|
||||
req->ring_index = 0;
|
||||
req->ring_ptr = req->ring;
|
||||
} else {
|
||||
req->ring_ptr++;
|
||||
}
|
||||
return (cont_entry_t *)req->ring_ptr;
|
||||
qla_req_ring_advance(ha, req);
|
||||
|
||||
return qla_req_ring_slot(ha, req);
|
||||
}
|
||||
|
||||
/* ha->hardware_lock supposed to be held on entry */
|
||||
@@ -2549,9 +2545,9 @@ static int qlt_24xx_build_ctio_pkt(struct qla_qpair *qpair,
|
||||
uint16_t temp;
|
||||
struct qla_tgt_cmd *cmd = prm->cmd;
|
||||
|
||||
pkt = (struct ctio7_to_24xx *)qpair->req->ring_ptr;
|
||||
pkt = (struct ctio7_to_24xx *)qla_req_ring_slot(qpair->hw, qpair->req);
|
||||
prm->pkt = pkt;
|
||||
memset(pkt, 0, sizeof(*pkt));
|
||||
memset(pkt, 0, qla_req_entry_size(qpair->hw));
|
||||
|
||||
pkt->entry_type = CTIO_TYPE7;
|
||||
pkt->entry_count = (uint8_t)prm->req_cnt;
|
||||
@@ -2600,11 +2596,12 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
|
||||
{
|
||||
int cnt;
|
||||
struct dsd64 *cur_dsd;
|
||||
struct qla_hw_data *ha = prm->cmd->qpair->hw;
|
||||
|
||||
/* Build continuation packets */
|
||||
while (prm->seg_cnt > 0) {
|
||||
cont_a64_entry_t *cont_pkt64 =
|
||||
(cont_a64_entry_t *)qlt_get_req_pkt(
|
||||
(cont_a64_entry_t *)qlt_get_req_pkt(ha,
|
||||
prm->cmd->qpair->req);
|
||||
|
||||
/*
|
||||
@@ -2614,7 +2611,7 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm)
|
||||
* that.
|
||||
*/
|
||||
|
||||
memset(cont_pkt64, 0, sizeof(*cont_pkt64));
|
||||
memset(cont_pkt64, 0, qla_req_entry_size(ha));
|
||||
|
||||
cont_pkt64->entry_count = 1;
|
||||
cont_pkt64->sys_define = 0;
|
||||
@@ -3012,9 +3009,9 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm)
|
||||
|
||||
ha = vha->hw;
|
||||
|
||||
pkt = (struct ctio_crc2_to_fw *)qpair->req->ring_ptr;
|
||||
pkt = (struct ctio_crc2_to_fw *)qla_req_ring_slot(ha, qpair->req);
|
||||
prm->pkt = pkt;
|
||||
memset(pkt, 0, sizeof(*pkt));
|
||||
memset(pkt, 0, qla_req_entry_size(ha));
|
||||
|
||||
ql_dbg_qp(ql_dbg_tgt, cmd->qpair, 0xe071,
|
||||
"qla_target(%d):%s: se_cmd[%p] CRC2 prot_op[0x%x] cmd prot sg:cnt[%p:%x] lba[%llu]\n",
|
||||
@@ -3306,7 +3303,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
|
||||
*/
|
||||
struct ctio7_to_24xx *ctio =
|
||||
(struct ctio7_to_24xx *)qlt_get_req_pkt(
|
||||
qpair->req);
|
||||
vha->hw, qpair->req);
|
||||
|
||||
ql_dbg_qp(ql_dbg_tgt, qpair, 0x305e,
|
||||
"Building additional status packet 0x%p.\n",
|
||||
@@ -3316,6 +3313,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type,
|
||||
* T10Dif: ctio_crc2_to_fw overlay ontop of
|
||||
* ctio7_to_24xx
|
||||
*/
|
||||
memset(ctio, 0, qla_req_entry_size(vha->hw));
|
||||
memcpy(ctio, pkt, sizeof(*ctio));
|
||||
/* reset back to CTIO7 */
|
||||
ctio->entry_count = 1;
|
||||
|
||||
@@ -306,6 +306,12 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (vha->hw->flags.t262_fail) {
|
||||
ql_dbg(ql_dbg_misc, vha, 0xd045,
|
||||
"%s: failed previously\n", __func__);
|
||||
qla27xx_skip_entry(ent, buf);
|
||||
goto done;
|
||||
}
|
||||
dwords = end - start + 1;
|
||||
if (buf) {
|
||||
buf += *len;
|
||||
@@ -314,7 +320,12 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha,
|
||||
ql_dbg(ql_dbg_async, vha, 0xffff,
|
||||
"%s: dump ram MB failed. Area %xh start %lxh end %lxh\n",
|
||||
__func__, area, start, end);
|
||||
return INVALID_ENTRY;
|
||||
|
||||
if (rc == QLA_FUNCTION_TIMEOUT)
|
||||
vha->hw->flags.t262_fail = 1;
|
||||
|
||||
qla27xx_skip_entry(ent, buf);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
*len += dwords * sizeof(uint32_t);
|
||||
@@ -536,13 +547,12 @@ qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha,
|
||||
{
|
||||
ql_dbg(ql_dbg_misc, vha, 0xd20d,
|
||||
"%s: scratch [%lx]\n", __func__, *len);
|
||||
qla27xx_insert32(0xaaaaaaaa, buf, len);
|
||||
qla27xx_insert32(0xbbbbbbbb, buf, len);
|
||||
qla27xx_insert32(0xcccccccc, buf, len);
|
||||
qla27xx_insert32(0xdddddddd, buf, len);
|
||||
qla27xx_insert32(*len + sizeof(uint32_t), buf, len);
|
||||
|
||||
/* The data format is based on entry type t260. */
|
||||
qla27xx_insert32(offsetof(struct device_reg_24xx, mailbox0), buf, len);
|
||||
qla27xx_insertbuf(vha->hw->mbregs, sizeof(vha->hw->mbregs), buf, len);
|
||||
if (buf)
|
||||
ent->t269.scratch_size = 5 * sizeof(uint32_t);
|
||||
ent->t269.scratch_size = sizeof(uint32_t) + sizeof(vha->hw->mbregs);
|
||||
|
||||
return qla27xx_next_entry(ent);
|
||||
}
|
||||
@@ -589,17 +599,37 @@ qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha,
|
||||
{
|
||||
ulong dwords = le32_to_cpu(ent->t272.count);
|
||||
ulong start = le32_to_cpu(ent->t272.addr);
|
||||
int rc;
|
||||
|
||||
ql_dbg(ql_dbg_misc, vha, 0xd210,
|
||||
"%s: rdremram [%lx]\n", __func__, *len);
|
||||
|
||||
if (vha->hw->flags.t272_fail) {
|
||||
ql_dbg(ql_dbg_misc, vha, 0xd04f,
|
||||
"%s: failed previously\n", __func__);
|
||||
qla27xx_skip_entry(ent, buf);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (buf) {
|
||||
ql_dbg(ql_dbg_misc, vha, 0xd02c,
|
||||
"%s: @%lx -> (%lx dwords)\n", __func__, start, dwords);
|
||||
buf += *len;
|
||||
qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf);
|
||||
rc = qla27xx_dump_mpi_ram(vha->hw, start, buf, dwords, &buf);
|
||||
if (rc != QLA_SUCCESS) {
|
||||
ql_log(ql_log_warn, vha, 0xd01b,
|
||||
"%s: dump mpi MB failed. Start %lxh dwords %lxh\n",
|
||||
__func__, start, dwords);
|
||||
|
||||
if (rc == QLA_FUNCTION_TIMEOUT)
|
||||
vha->hw->flags.t272_fail = 1;
|
||||
|
||||
qla27xx_skip_entry(ent, buf);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
*len += dwords * sizeof(uint32_t);
|
||||
|
||||
done:
|
||||
return qla27xx_next_entry(ent);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
/*
|
||||
* Driver version
|
||||
*/
|
||||
#define QLA2XXX_VERSION "10.02.10.100-k"
|
||||
#define QLA2XXX_VERSION "12.00.00.2607b2"
|
||||
|
||||
#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
|
||||
|
||||
@@ -1187,8 +1187,10 @@ blk_status_t scsi_alloc_sgtables(struct scsi_cmnd *cmd)
|
||||
if (blk_rq_bytes(rq) & rq->q->limits.dma_pad_mask) {
|
||||
unsigned int pad_len =
|
||||
(rq->q->limits.dma_pad_mask & ~blk_rq_bytes(rq)) + 1;
|
||||
unsigned int data_len = last_sg->length;
|
||||
|
||||
last_sg->length += pad_len;
|
||||
sg_zero_buffer(last_sg, 1, pad_len, data_len);
|
||||
cmd->extra_len += pad_len;
|
||||
}
|
||||
|
||||
|
||||
+35
-20
@@ -958,6 +958,21 @@ static unsigned char sd_setup_protect_cmnd(struct scsi_cmnd *scmd,
|
||||
return protect;
|
||||
}
|
||||
|
||||
static void sd_uninit_command(struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct request *rq = scsi_cmd_to_rq(cmd);
|
||||
struct scsi_device *sdp = cmd->device;
|
||||
|
||||
if (!(rq->rq_flags & RQF_SPECIAL_PAYLOAD))
|
||||
return;
|
||||
|
||||
if (sdp->sector_size > PAGE_SIZE)
|
||||
mempool_free(rq->special_vec.bv_page, sd_large_page_pool);
|
||||
else
|
||||
mempool_free(rq->special_vec.bv_page, sd_page_pool);
|
||||
rq->rq_flags &= ~RQF_SPECIAL_PAYLOAD;
|
||||
}
|
||||
|
||||
static void *sd_set_special_bvec(struct scsi_cmnd *cmd, unsigned int data_len)
|
||||
{
|
||||
struct page *page;
|
||||
@@ -990,6 +1005,7 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd)
|
||||
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
|
||||
unsigned int data_len = 24;
|
||||
char *buf;
|
||||
blk_status_t ret;
|
||||
|
||||
buf = sd_set_special_bvec(cmd, data_len);
|
||||
if (!buf)
|
||||
@@ -1008,7 +1024,10 @@ static blk_status_t sd_setup_unmap_cmnd(struct scsi_cmnd *cmd)
|
||||
cmd->transfersize = data_len;
|
||||
rq->timeout = SD_TIMEOUT;
|
||||
|
||||
return scsi_alloc_sgtables(cmd);
|
||||
ret = scsi_alloc_sgtables(cmd);
|
||||
if (ret != BLK_STS_OK)
|
||||
sd_uninit_command(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sd_config_atomic(struct scsi_disk *sdkp, struct queue_limits *lim)
|
||||
@@ -1079,6 +1098,7 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd,
|
||||
u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq));
|
||||
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
|
||||
u32 data_len = sdp->sector_size;
|
||||
blk_status_t ret;
|
||||
|
||||
if (!sd_set_special_bvec(cmd, data_len))
|
||||
return BLK_STS_RESOURCE;
|
||||
@@ -1094,7 +1114,10 @@ static blk_status_t sd_setup_write_same16_cmnd(struct scsi_cmnd *cmd,
|
||||
cmd->transfersize = data_len;
|
||||
rq->timeout = unmap ? SD_TIMEOUT : SD_WRITE_SAME_TIMEOUT;
|
||||
|
||||
return scsi_alloc_sgtables(cmd);
|
||||
ret = scsi_alloc_sgtables(cmd);
|
||||
if (ret != BLK_STS_OK)
|
||||
sd_uninit_command(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,
|
||||
@@ -1106,6 +1129,7 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,
|
||||
u64 lba = sectors_to_logical(sdp, blk_rq_pos(rq));
|
||||
u32 nr_blocks = sectors_to_logical(sdp, blk_rq_sectors(rq));
|
||||
u32 data_len = sdp->sector_size;
|
||||
blk_status_t ret;
|
||||
|
||||
if (!sd_set_special_bvec(cmd, data_len))
|
||||
return BLK_STS_RESOURCE;
|
||||
@@ -1121,7 +1145,10 @@ static blk_status_t sd_setup_write_same10_cmnd(struct scsi_cmnd *cmd,
|
||||
cmd->transfersize = data_len;
|
||||
rq->timeout = unmap ? SD_TIMEOUT : SD_WRITE_SAME_TIMEOUT;
|
||||
|
||||
return scsi_alloc_sgtables(cmd);
|
||||
ret = scsi_alloc_sgtables(cmd);
|
||||
if (ret != BLK_STS_OK)
|
||||
sd_uninit_command(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static blk_status_t sd_setup_write_zeroes_cmnd(struct scsi_cmnd *cmd)
|
||||
@@ -1550,20 +1577,6 @@ static blk_status_t sd_init_command(struct scsi_cmnd *cmd)
|
||||
}
|
||||
}
|
||||
|
||||
static void sd_uninit_command(struct scsi_cmnd *SCpnt)
|
||||
{
|
||||
struct request *rq = scsi_cmd_to_rq(SCpnt);
|
||||
struct scsi_device *sdp = SCpnt->device;
|
||||
unsigned sector_size = sdp->sector_size;
|
||||
|
||||
if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) {
|
||||
if (sector_size > PAGE_SIZE)
|
||||
mempool_free(rq->special_vec.bv_page, sd_large_page_pool);
|
||||
else
|
||||
mempool_free(rq->special_vec.bv_page, sd_page_pool);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sd_need_revalidate(struct gendisk *disk, struct scsi_disk *sdkp)
|
||||
{
|
||||
if (sdkp->device->removable || sdkp->write_prot) {
|
||||
@@ -2406,8 +2419,8 @@ static int sd_done(struct scsi_cmnd *SCpnt)
|
||||
}
|
||||
sdkp->medium_access_timed_out = 0;
|
||||
|
||||
if (!scsi_status_is_check_condition(result) &&
|
||||
(!sense_valid || sense_deferred))
|
||||
if (!scsi_status_is_check_condition(result) ||
|
||||
!sense_valid || sense_deferred)
|
||||
goto out;
|
||||
|
||||
switch (sshdr.sense_key) {
|
||||
@@ -4089,7 +4102,9 @@ static int sd_probe(struct scsi_device *sdp)
|
||||
if (sdp->sector_size > PAGE_SIZE) {
|
||||
if (sd_large_pool_create()) {
|
||||
error = -ENOMEM;
|
||||
goto out_free_index;
|
||||
device_unregister(&sdkp->disk_dev);
|
||||
put_disk(gd);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,11 +34,11 @@
|
||||
#define BUILD_TIMESTAMP
|
||||
#endif
|
||||
|
||||
#define DRIVER_VERSION "2.1.36-026"
|
||||
#define DRIVER_VERSION "2.1.42-011"
|
||||
#define DRIVER_MAJOR 2
|
||||
#define DRIVER_MINOR 1
|
||||
#define DRIVER_RELEASE 36
|
||||
#define DRIVER_REVISION 26
|
||||
#define DRIVER_RELEASE 42
|
||||
#define DRIVER_REVISION 11
|
||||
|
||||
#define DRIVER_NAME "Microchip SmartPQI Driver (v" \
|
||||
DRIVER_VERSION BUILD_TIMESTAMP ")"
|
||||
@@ -66,6 +66,12 @@ static struct pqi_cmd_priv *pqi_cmd_priv(struct scsi_cmnd *cmd)
|
||||
return scsi_cmd_priv(cmd);
|
||||
}
|
||||
|
||||
static int pqi_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
|
||||
{
|
||||
memset(pqi_cmd_priv(cmd), 0, sizeof(struct pqi_cmd_priv));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pqi_verify_structures(void);
|
||||
static void pqi_take_ctrl_offline(struct pqi_ctrl_info *ctrl_info,
|
||||
enum pqi_ctrl_shutdown_reason ctrl_shutdown_reason);
|
||||
@@ -5958,6 +5964,17 @@ void pqi_prep_for_scsi_done(struct scsi_cmnd *scmd)
|
||||
struct pqi_scsi_dev *device;
|
||||
struct completion *wait;
|
||||
|
||||
/*
|
||||
* Clear the AIO-retry marker on final completion so the tag
|
||||
* starts clean on its next dispatch. On DID_IMM_RETRY leave
|
||||
* it intact: pqi_aio_io_complete() sets DID_IMM_RETRY and
|
||||
* bumps the marker to steer the requeue onto the RAID path,
|
||||
* and pqi_process_raid_io_error() consumes the non-zero
|
||||
* marker to offline a misbehaving drive.
|
||||
*/
|
||||
if (host_byte(scmd->result) != DID_IMM_RETRY)
|
||||
pqi_cmd_priv(scmd)->this_residual = 0;
|
||||
|
||||
if (!scmd->device) {
|
||||
set_host_byte(scmd, DID_NO_CONNECT);
|
||||
return;
|
||||
@@ -6918,6 +6935,144 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pqi_big_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg)
|
||||
{
|
||||
int rc;
|
||||
char *kernel_buffer = NULL;
|
||||
u16 iu_length;
|
||||
size_t sense_data_length;
|
||||
BIG_IOCTL_Command_struct iocommand;
|
||||
struct pqi_raid_path_request request;
|
||||
struct pqi_raid_error_info pqi_error_info;
|
||||
struct ciss_error_info ciss_error_info;
|
||||
|
||||
if (pqi_ctrl_offline(ctrl_info))
|
||||
return -ENXIO;
|
||||
if (pqi_ofa_in_progress(ctrl_info) && pqi_ctrl_blocked(ctrl_info))
|
||||
return -EBUSY;
|
||||
if (!arg)
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_RAWIO))
|
||||
return -EPERM;
|
||||
if (copy_from_user(&iocommand, arg, sizeof(iocommand)))
|
||||
return -EFAULT;
|
||||
if (iocommand.buf_size < 1 &&
|
||||
iocommand.Request.Type.Direction != XFER_NONE)
|
||||
return -EINVAL;
|
||||
if (iocommand.Request.CDBLen > sizeof(request.cdb))
|
||||
return -EINVAL;
|
||||
if (iocommand.Request.Type.Type != TYPE_CMD)
|
||||
return -EINVAL;
|
||||
|
||||
switch (iocommand.Request.Type.Direction) {
|
||||
case XFER_NONE:
|
||||
case XFER_WRITE:
|
||||
case XFER_READ:
|
||||
case XFER_READ | XFER_WRITE:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (iocommand.buf_size > 0) {
|
||||
kernel_buffer = kmalloc(iocommand.buf_size, GFP_KERNEL);
|
||||
if (!kernel_buffer)
|
||||
return -ENOMEM;
|
||||
if (iocommand.Request.Type.Direction & XFER_WRITE) {
|
||||
if (copy_from_user(kernel_buffer, iocommand.buf,
|
||||
iocommand.buf_size)) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
memset(kernel_buffer, 0, iocommand.buf_size);
|
||||
}
|
||||
}
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
|
||||
request.header.iu_type = PQI_REQUEST_IU_RAID_PATH_IO;
|
||||
iu_length = offsetof(struct pqi_raid_path_request, sg_descriptors) -
|
||||
PQI_REQUEST_HEADER_LENGTH;
|
||||
memcpy(request.lun_number, iocommand.LUN_info.LunAddrBytes, sizeof(request.lun_number));
|
||||
memcpy(request.cdb, iocommand.Request.CDB, iocommand.Request.CDBLen);
|
||||
request.additional_cdb_bytes_usage = SOP_ADDITIONAL_CDB_BYTES_0;
|
||||
|
||||
switch (iocommand.Request.Type.Direction) {
|
||||
case XFER_NONE:
|
||||
request.data_direction = SOP_NO_DIRECTION_FLAG;
|
||||
break;
|
||||
case XFER_WRITE:
|
||||
request.data_direction = SOP_WRITE_FLAG;
|
||||
break;
|
||||
case XFER_READ:
|
||||
request.data_direction = SOP_READ_FLAG;
|
||||
break;
|
||||
case XFER_READ | XFER_WRITE:
|
||||
request.data_direction = SOP_BIDIRECTIONAL;
|
||||
break;
|
||||
}
|
||||
|
||||
request.task_attribute = SOP_TASK_ATTRIBUTE_SIMPLE;
|
||||
|
||||
if (iocommand.buf_size > 0) {
|
||||
put_unaligned_le32(iocommand.buf_size, &request.buffer_length);
|
||||
|
||||
rc = pqi_map_single(ctrl_info->pci_dev,
|
||||
&request.sg_descriptors[0], kernel_buffer,
|
||||
iocommand.buf_size, DMA_BIDIRECTIONAL);
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
iu_length += sizeof(request.sg_descriptors[0]);
|
||||
}
|
||||
|
||||
put_unaligned_le16(iu_length, &request.header.iu_length);
|
||||
|
||||
if (ctrl_info->raid_iu_timeout_supported)
|
||||
put_unaligned_le32(iocommand.Request.Timeout, &request.timeout);
|
||||
|
||||
rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header,
|
||||
PQI_SYNC_FLAGS_INTERRUPTABLE, &pqi_error_info);
|
||||
|
||||
if (iocommand.buf_size > 0)
|
||||
pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, DMA_BIDIRECTIONAL);
|
||||
|
||||
memset(&iocommand.error_info, 0, sizeof(iocommand.error_info));
|
||||
|
||||
if (rc == 0) {
|
||||
pqi_error_info_to_ciss(&pqi_error_info, &ciss_error_info);
|
||||
iocommand.error_info.ScsiStatus = ciss_error_info.scsi_status;
|
||||
iocommand.error_info.CommandStatus = ciss_error_info.command_status;
|
||||
sense_data_length = ciss_error_info.sense_data_length;
|
||||
if (sense_data_length) {
|
||||
if (sense_data_length > sizeof(iocommand.error_info.SenseInfo))
|
||||
sense_data_length = sizeof(iocommand.error_info.SenseInfo);
|
||||
memcpy(iocommand.error_info.SenseInfo,
|
||||
pqi_error_info.data, sense_data_length);
|
||||
iocommand.error_info.SenseLen = sense_data_length;
|
||||
}
|
||||
}
|
||||
|
||||
if (copy_to_user(arg, &iocommand, sizeof(iocommand))) {
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rc == 0 && iocommand.buf_size > 0 &&
|
||||
(iocommand.Request.Type.Direction & XFER_READ)) {
|
||||
if (copy_to_user(iocommand.buf, kernel_buffer,
|
||||
iocommand.buf_size)) {
|
||||
rc = -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
kfree(kernel_buffer);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pqi_ioctl(struct scsi_device *sdev, unsigned int cmd,
|
||||
void __user *arg)
|
||||
{
|
||||
@@ -6941,6 +7096,12 @@ static int pqi_ioctl(struct scsi_device *sdev, unsigned int cmd,
|
||||
case CCISS_PASSTHRU:
|
||||
rc = pqi_passthru_ioctl(ctrl_info, arg);
|
||||
break;
|
||||
case CCISS_BIG_PASSTHRU:
|
||||
rc = pqi_big_passthru_ioctl(ctrl_info, arg);
|
||||
break;
|
||||
case CCISS_BIG_PASSTHRU_SUPPORTED:
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
break;
|
||||
@@ -7612,6 +7773,7 @@ static const struct scsi_host_template pqi_driver_template = {
|
||||
.sdev_groups = pqi_sdev_groups,
|
||||
.shost_groups = pqi_shost_groups,
|
||||
.cmd_size = sizeof(struct pqi_cmd_priv),
|
||||
.init_cmd_priv = pqi_init_cmd_priv,
|
||||
};
|
||||
|
||||
static int pqi_register_scsi(struct pqi_ctrl_info *ctrl_info)
|
||||
@@ -10152,10 +10314,30 @@ static const struct pci_device_id pqi_pci_id_table[] = {
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x207d, 0x4240)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x207d, 0x4246)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x207d, 0x4256)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x207d, 0x4356)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x207d, 0x4840)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x207d, 0x4940)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x207d, 0x4a46)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
PCI_VENDOR_ID_ADVANTECH, 0x8312)
|
||||
@@ -10340,6 +10522,18 @@ static const struct pci_device_id pqi_pci_id_table[] = {
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1cf2, 0x544f)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1cf2, 0x5451)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1cf2, 0x5452)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1cf2, 0x5453)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1cf2, 0x54da)
|
||||
@@ -10380,6 +10574,10 @@ static const struct pci_device_id pqi_pci_id_table[] = {
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1f3f, 0x0610)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
0x1f3f, 0x0670)
|
||||
},
|
||||
{
|
||||
PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x028f,
|
||||
PCI_VENDOR_ID_LENOVO, 0x0220)
|
||||
|
||||
@@ -520,6 +520,36 @@ static void storvsc_host_scan(struct work_struct *work)
|
||||
scsi_scan_host(host);
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
|
||||
static int storvsc_user_scan(struct Scsi_Host *host,
|
||||
unsigned int channel,
|
||||
unsigned int id,
|
||||
u64 lun)
|
||||
{
|
||||
unsigned int first_channel, last_channel;
|
||||
unsigned int first_id, end_id;
|
||||
unsigned int ch, target;
|
||||
|
||||
if ((channel != SCAN_WILD_CARD && channel > host->max_channel) ||
|
||||
(id != SCAN_WILD_CARD && id >= host->max_id) ||
|
||||
(lun != SCAN_WILD_CARD && lun >= host->max_lun))
|
||||
return -EINVAL;
|
||||
|
||||
first_channel = channel == SCAN_WILD_CARD ? 0 : channel;
|
||||
last_channel = channel == SCAN_WILD_CARD ? host->max_channel : channel;
|
||||
first_id = id == SCAN_WILD_CARD ? 0 : id;
|
||||
end_id = id == SCAN_WILD_CARD ? host->max_id : id + 1;
|
||||
|
||||
for (ch = first_channel; ch <= last_channel; ch++) {
|
||||
for (target = first_id; target < end_id; target++)
|
||||
scsi_scan_target(&host->shost_gendev, ch, target, lun,
|
||||
SCSI_SCAN_MANUAL);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void storvsc_remove_lun(struct work_struct *work)
|
||||
{
|
||||
struct storvsc_scan_work *wrk;
|
||||
@@ -2232,6 +2262,8 @@ static int __init storvsc_drv_init(void)
|
||||
fc_transport_template = fc_attach_transport(&fc_transport_functions);
|
||||
if (!fc_transport_template)
|
||||
return -ENODEV;
|
||||
|
||||
fc_transport_template->user_scan = storvsc_user_scan;
|
||||
#endif
|
||||
|
||||
ret = vmbus_driver_register(&storvsc_drv);
|
||||
|
||||
@@ -122,10 +122,11 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
|
||||
struct virtio_scsi_cmd *cmd = buf;
|
||||
struct scsi_cmnd *sc = cmd->sc;
|
||||
struct virtio_scsi_cmd_resp *resp = &cmd->resp.cmd;
|
||||
unsigned sense_len = virtio32_to_cpu(vscsi->vdev, resp->sense_len);
|
||||
|
||||
dev_dbg(&sc->device->sdev_gendev,
|
||||
"cmd %p response %u status %#02x sense_len %u\n",
|
||||
sc, resp->response, resp->status, resp->sense_len);
|
||||
sc, resp->response, resp->status, sense_len);
|
||||
|
||||
sc->result = resp->status;
|
||||
virtscsi_compute_resid(sc, virtio32_to_cpu(vscsi->vdev, resp->resid));
|
||||
@@ -166,13 +167,10 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
|
||||
break;
|
||||
}
|
||||
|
||||
WARN_ON(virtio32_to_cpu(vscsi->vdev, resp->sense_len) >
|
||||
VIRTIO_SCSI_SENSE_SIZE);
|
||||
WARN_ON(sense_len > VIRTIO_SCSI_SENSE_SIZE);
|
||||
if (resp->sense_len) {
|
||||
memcpy(sc->sense_buffer, resp->sense,
|
||||
min_t(u32,
|
||||
virtio32_to_cpu(vscsi->vdev, resp->sense_len),
|
||||
VIRTIO_SCSI_SENSE_SIZE));
|
||||
min_t(u32, sense_len, VIRTIO_SCSI_SENSE_SIZE));
|
||||
}
|
||||
|
||||
scsi_done(sc);
|
||||
@@ -288,8 +286,9 @@ static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi,
|
||||
struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
|
||||
unsigned int target = event->lun[1];
|
||||
unsigned int lun = (event->lun[2] << 8) | event->lun[3];
|
||||
unsigned int reason = virtio32_to_cpu(vscsi->vdev, event->reason);
|
||||
|
||||
switch (virtio32_to_cpu(vscsi->vdev, event->reason)) {
|
||||
switch (reason) {
|
||||
case VIRTIO_SCSI_EVT_RESET_RESCAN:
|
||||
if (lun == 0) {
|
||||
scsi_scan_target(&shost->shost_gendev, 0, target,
|
||||
@@ -309,7 +308,7 @@ static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi,
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_info("Unsupported virtio scsi event reason %x\n", event->reason);
|
||||
pr_info("Unsupported virtio scsi event reason %x\n", reason);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +408,8 @@ static void virtscsi_handle_event(struct work_struct *work)
|
||||
virtscsi_handle_param_change(vscsi, event);
|
||||
break;
|
||||
default:
|
||||
pr_err("Unsupported virtio scsi event %x\n", event->event);
|
||||
pr_err("Unsupported virtio scsi event %x\n",
|
||||
virtio32_to_cpu(vscsi->vdev, event->event));
|
||||
}
|
||||
virtscsi_kick_event(vscsi, event_node);
|
||||
}
|
||||
|
||||
@@ -50,25 +50,25 @@ static struct zorro_driver_data {
|
||||
static struct zorro_device_id zorro7xx_zorro_tbl[] = {
|
||||
{
|
||||
.id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS,
|
||||
.driver_data = (unsigned long)&zorro7xx_driver_data[0],
|
||||
.driver_data_ptr = &zorro7xx_driver_data[0],
|
||||
},
|
||||
{
|
||||
.id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx,
|
||||
.driver_data = (unsigned long)&zorro7xx_driver_data[1],
|
||||
.driver_data_ptr = &zorro7xx_driver_data[1],
|
||||
},
|
||||
{
|
||||
.id = ZORRO_PROD_CBM_A4091_1,
|
||||
.driver_data = (unsigned long)&zorro7xx_driver_data[2],
|
||||
.driver_data_ptr = &zorro7xx_driver_data[2],
|
||||
},
|
||||
{
|
||||
.id = ZORRO_PROD_CBM_A4091_2,
|
||||
.driver_data = (unsigned long)&zorro7xx_driver_data[2],
|
||||
.driver_data_ptr = &zorro7xx_driver_data[2],
|
||||
},
|
||||
{
|
||||
.id = ZORRO_PROD_GVP_GFORCE_040_060,
|
||||
.driver_data = (unsigned long)&zorro7xx_driver_data[3],
|
||||
.driver_data_ptr = &zorro7xx_driver_data[3],
|
||||
},
|
||||
{ 0 }
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(zorro, zorro7xx_zorro_tbl);
|
||||
|
||||
@@ -77,11 +77,11 @@ static int zorro7xx_init_one(struct zorro_dev *z,
|
||||
{
|
||||
struct Scsi_Host *host;
|
||||
struct NCR_700_Host_Parameters *hostdata;
|
||||
struct zorro_driver_data *zdd;
|
||||
const struct zorro_driver_data *zdd;
|
||||
unsigned long board, ioaddr;
|
||||
|
||||
board = zorro_resource_start(z);
|
||||
zdd = (struct zorro_driver_data *)ent->driver_data;
|
||||
zdd = ent->driver_data_ptr;
|
||||
|
||||
if (zdd->absolute) {
|
||||
ioaddr = zdd->offset;
|
||||
|
||||
@@ -706,7 +706,7 @@ static const struct zorro_device_id zorro_esp_zorro_tbl[] = {
|
||||
.id = ZORRO_ID(PHASE5, 0x19, 0),
|
||||
.driver_data = ZORRO_CYBERII,
|
||||
},
|
||||
{ 0 }
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(zorro, zorro_esp_zorro_tbl);
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ static ssize_t ufs_saved_err_write(struct file *file, const char __user *buf,
|
||||
char val_str[16] = { };
|
||||
int val, ret;
|
||||
|
||||
if (count > sizeof(val_str))
|
||||
if (count >= sizeof(val_str))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(val_str, buf, count))
|
||||
return -EFAULT;
|
||||
|
||||
@@ -296,14 +296,20 @@ static int ufshcd_mcq_get_tag(struct ufs_hba *hba, struct cq_entry *cqe)
|
||||
if (hba->ufs_version >= ufshci_version(4, 1))
|
||||
return cqe->task_tag;
|
||||
|
||||
/* sizeof(struct utp_transfer_cmd_desc) must be a multiple of 128 */
|
||||
/* Both UCD types must have a size that is a multiple of 128 bytes */
|
||||
BUILD_BUG_ON(sizeof(struct utp_transfer_cmd_desc) & GENMASK(6, 0));
|
||||
BUILD_BUG_ON(sizeof(struct utp_devman_cmd_desc) & GENMASK(6, 0));
|
||||
|
||||
/* Bits 63:7 UCD base address, 6:5 are reserved, 4:0 is SQ ID */
|
||||
addr = (le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA) -
|
||||
hba->ucdl_dma_addr;
|
||||
addr = le64_to_cpu(cqe->command_desc_base_addr) & CQE_UCD_BA;
|
||||
|
||||
return div_u64(addr, ufshcd_get_ucd_size(hba));
|
||||
/* The devman UCD is outside the pool; return its reserved tag. */
|
||||
if (unlikely(addr == hba->devman_ucd_dma_addr))
|
||||
return hba->dev_cmd.tag;
|
||||
|
||||
/* Pool entries follow the reserved tags. */
|
||||
return div_u64(addr - hba->ucdl_dma_addr, ufshcd_get_ucd_size(hba)) +
|
||||
UFSHCD_NUM_RESERVED;
|
||||
}
|
||||
|
||||
static void ufshcd_mcq_process_cqe(struct ufs_hba *hba,
|
||||
|
||||
@@ -69,7 +69,11 @@ static int ufs_rpmb_route_frames(struct device *dev, u8 *req, unsigned int req_l
|
||||
|
||||
hba = ufs_rpmb->hba;
|
||||
|
||||
req_type = be16_to_cpu(frm_out->req_resp);
|
||||
/* req_resp is at the end of an RPMB frame. */
|
||||
if (req_len < sizeof(*frm_out))
|
||||
return -EINVAL;
|
||||
|
||||
req_type = get_unaligned_be16(&frm_out->req_resp);
|
||||
|
||||
switch (req_type) {
|
||||
case RPMB_PROGRAM_KEY:
|
||||
@@ -107,7 +111,7 @@ static int ufs_rpmb_route_frames(struct device *dev, u8 *req, unsigned int req_l
|
||||
struct rpmb_frame *frm_resp = (struct rpmb_frame *)resp;
|
||||
|
||||
memset(frm_resp, 0, sizeof(*frm_resp));
|
||||
frm_resp->req_resp = cpu_to_be16(RPMB_RESULT_READ);
|
||||
put_unaligned_be16(RPMB_RESULT_READ, &frm_resp->req_resp);
|
||||
ret = ufs_sec_submit(hba, protocol_id, resp, resp_len, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "Result read request failed with ret=%d\n", ret);
|
||||
|
||||
@@ -54,6 +54,7 @@ static const char *ufs_hs_gear_to_string(enum ufs_hs_gear_tag gear)
|
||||
case UFS_HS_G3: return "HS_GEAR3";
|
||||
case UFS_HS_G4: return "HS_GEAR4";
|
||||
case UFS_HS_G5: return "HS_GEAR5";
|
||||
case UFS_HS_G6: return "HS_GEAR6";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user