/* * Scsi Host Layer for MPT (Message Passing Technology) based controllers * * This code is based on drivers/scsi/mpt3sas/mpt3sas_scsih.c * Copyright (C) 2012-2014 LSI Corporation * Copyright (C) 2013-2014 Avago Technologies * (mailto: MPT-FusionLinux.pdl@avagotech.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * NO WARRANTY * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is * solely responsible for determining the appropriateness of using and * distributing the Program and assumes all risks associated with its * exercise of rights under this Agreement, including but not limited to * the risks and costs of program errors, damage to or loss of data, * programs or equipment, and unavailability or interruption of operations.
* DISCLAIMER OF LIABILITY * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
* You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, * USA.
*/
/* scsi-mid layer global parmeter is max_report_luns, which is 511 */ #define MPT3SAS_MAX_LUN (16895) static u64 max_lun = MPT3SAS_MAX_LUN;
module_param(max_lun, ullong, 0444);
MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
static ushort hbas_to_enumerate;
module_param(hbas_to_enumerate, ushort, 0444);
MODULE_PARM_DESC(hbas_to_enumerate, " 0 - enumerates both SAS 2.0 & SAS 3.0 generation HBAs\n \
1 - enumerates only SAS 2.0 generation HBAs\n \
2 - enumerates only SAS 3.0 generation HBAs (default=0)");
/* diag_buffer_enable is bitwise * bit 0 set = TRACE * bit 1 set = SNAPSHOT * bit 2 set = EXTENDED * * Either bit can be set, or both
*/ staticint diag_buffer_enable = -1;
module_param(diag_buffer_enable, int, 0444);
MODULE_PARM_DESC(diag_buffer_enable, " post diag buffers (TRACE=1/SNAPSHOT=2/EXTENDED=4/default=0)"); staticint disable_discovery = -1;
module_param(disable_discovery, int, 0444);
MODULE_PARM_DESC(disable_discovery, " disable discovery ");
staticbool enable_sdev_max_qd;
module_param(enable_sdev_max_qd, bool, 0444);
MODULE_PARM_DESC(enable_sdev_max_qd, "Enable sdev max qd as can_queue, def=disabled(0)");
staticint multipath_on_hba = -1;
module_param(multipath_on_hba, int, 0);
MODULE_PARM_DESC(multipath_on_hba, "Multipath support to add same target device\n\t\t" "as many times as it is visible to HBA from various paths\n\t\t" "(by default:\n\t\t" "\t SAS 2.0 & SAS 3.0 HBA - This will be disabled,\n\t\t" "\t SAS 3.5 HBA - This will be enabled)");
/* * SAS Log info code for a NCQ collateral abort after an NCQ error: * IOC_LOGINFO_PREFIX_PL | PL_LOGINFO_CODE_SATA_NCQ_FAIL_ALL_CMDS_AFTR_ERR * See: drivers/message/fusion/lsi/mpi_log_sas.h
*/ #define IOC_LOGINFO_SATA_NCQ_FAIL_AFTER_ERR 0x31080000
/** * struct fw_event_work - firmware event struct * @list: link list framework * @work: work object (ioc->fault_reset_work_q) * @ioc: per adapter object * @device_handle: device handle * @VF_ID: virtual function id * @VP_ID: virtual port id * @ignore: flag meaning this event has been marked to ignore * @event: firmware event MPI2_EVENT_XXX defined in mpi2_ioc.h * @refcount: kref for this event * @event_data: reply event data payload follows * * This object stored on ioc->fw_event_list.
*/ struct fw_event_work { struct list_head list; struct work_struct work;
/** * struct _scsi_io_transfer - scsi io transfer * @handle: sas device handle (assigned by firmware) * @is_raid: flag set for hidden raid components * @dir: DMA_TO_DEVICE, DMA_FROM_DEVICE, * @data_length: data transfer length * @data_dma: dma pointer to data * @sense: sense data * @lun: lun number * @cdb_length: cdb length * @cdb: cdb contents * @timeout: timeout for this command * @VF_ID: virtual function id * @VP_ID: virtual port id * @valid_reply: flag set for reply message * @sense_length: sense length * @ioc_status: ioc status * @scsi_state: scsi state * @scsi_status: scsi staus * @log_info: log information * @transfer_length: data length transfer when there is a reply message * * Used for sending internal scsi commands to devices within this module. * Refer to _scsi_send_scsi_io().
*/ struct _scsi_io_transfer {
u16 handle;
u8 is_raid; enum dma_data_direction dir;
u32 data_length;
dma_addr_t data_dma;
u8 sense[SCSI_SENSE_BUFFERSIZE];
u32 lun;
u8 cdb_length;
u8 cdb[32];
u8 timeout;
u8 VF_ID;
u8 VP_ID;
u8 valid_reply; /* the following bits are only valid when 'valid_reply = 1' */
u32 sense_length;
u16 ioc_status;
u8 scsi_state;
u8 scsi_status;
u32 log_info;
u32 transfer_length;
};
/** * _scsih_set_debug_level - global setting of ioc->logging_level. * @val: value of the parameter to be set * @kp: pointer to kernel_param structure * * Note: The logging levels are defined in mpt3sas_debug.h.
*/ staticint
_scsih_set_debug_level(constchar *val, conststruct kernel_param *kp)
{ int ret = param_set_int(val, kp); struct MPT3SAS_ADAPTER *ioc;
/** * _scsih_srch_boot_sas_address - search based on sas_address * @sas_address: sas address * @boot_device: boot device object from bios page 2 * * Return: 1 when there's a match, 0 means no match.
*/ staticinlineint
_scsih_srch_boot_sas_address(u64 sas_address,
Mpi2BootDeviceSasWwid_t *boot_device)
{ return (sas_address == le64_to_cpu(boot_device->SASAddress)) ? 1 : 0;
}
/** * _scsih_srch_boot_device_name - search based on device name * @device_name: device name specified in INDENTIFY fram * @boot_device: boot device object from bios page 2 * * Return: 1 when there's a match, 0 means no match.
*/ staticinlineint
_scsih_srch_boot_device_name(u64 device_name,
Mpi2BootDeviceDeviceName_t *boot_device)
{ return (device_name == le64_to_cpu(boot_device->DeviceName)) ? 1 : 0;
}
/** * _scsih_srch_boot_encl_slot - search based on enclosure_logical_id/slot * @enclosure_logical_id: enclosure logical id * @slot_number: slot number * @boot_device: boot device object from bios page 2 * * Return: 1 when there's a match, 0 means no match.
*/ staticinlineint
_scsih_srch_boot_encl_slot(u64 enclosure_logical_id, u16 slot_number,
Mpi2BootDeviceEnclosureSlot_t *boot_device)
{ return (enclosure_logical_id == le64_to_cpu(boot_device->
EnclosureLogicalID) && slot_number == le16_to_cpu(boot_device->
SlotNumber)) ? 1 : 0;
}
/** * mpt3sas_get_port_by_id - get hba port entry corresponding to provided * port number from port list * @ioc: per adapter object * @port_id: port number * @bypass_dirty_port_flag: when set look the matching hba port entry even * if hba port entry is marked as dirty. * * Search for hba port entry corresponding to provided port number, * if available return port object otherwise return NULL.
*/ struct hba_port *
mpt3sas_get_port_by_id(struct MPT3SAS_ADAPTER *ioc,
u8 port_id, u8 bypass_dirty_port_flag)
{ struct hba_port *port, *port_next;
/* * When multipath_on_hba is disabled then * search the hba_port entry using default * port id i.e. 255
*/ if (!ioc->multipath_on_hba)
port_id = MULTIPATH_DISABLED_PORT_ID;
list_for_each_entry_safe(port, port_next,
&ioc->port_table_list, list) { if (port->port_id != port_id) continue; if (bypass_dirty_port_flag) return port; if (port->flags & HBA_PORT_FLAG_DIRTY_PORT) continue; return port;
}
/* * Allocate hba_port object for default port id (i.e. 255) * when multipath_on_hba is disabled for the HBA. * And add this object to port_table_list.
*/ if (!ioc->multipath_on_hba) {
port = kzalloc(sizeof(struct hba_port), GFP_ATOMIC); if (!port) return NULL;
/** * _scsih_is_boot_device - search for matching boot device. * @sas_address: sas address * @device_name: device name specified in INDENTIFY fram * @enclosure_logical_id: enclosure logical id * @slot: slot number * @form: specifies boot device form * @boot_device: boot device object from bios page 2 * * Return: 1 when there's a match, 0 means no match.
*/ staticint
_scsih_is_boot_device(u64 sas_address, u64 device_name,
u64 enclosure_logical_id, u16 slot, u8 form,
Mpi2BiosPage2BootDevice_t *boot_device)
{ int rc = 0;
switch (form) { case MPI2_BIOSPAGE2_FORM_SAS_WWID: if (!sas_address) break;
rc = _scsih_srch_boot_sas_address(
sas_address, &boot_device->SasWwid); break; case MPI2_BIOSPAGE2_FORM_ENCLOSURE_SLOT: if (!enclosure_logical_id) break;
rc = _scsih_srch_boot_encl_slot(
enclosure_logical_id,
slot, &boot_device->EnclosureSlot); break; case MPI2_BIOSPAGE2_FORM_DEVICE_NAME: if (!device_name) break;
rc = _scsih_srch_boot_device_name(
device_name, &boot_device->DeviceName); break; case MPI2_BIOSPAGE2_FORM_NO_DEVICE_SPECIFIED: break;
}
return rc;
}
/** * _scsih_get_sas_address - set the sas_address for given device handle * @ioc: ? * @handle: device handle * @sas_address: sas address * * Return: 0 success, non-zero when failure
*/ staticint
_scsih_get_sas_address(struct MPT3SAS_ADAPTER *ioc, u16 handle,
u64 *sas_address)
{
Mpi2SasDevicePage0_t sas_device_pg0;
Mpi2ConfigReply_t mpi_reply;
u32 ioc_status;
*sas_address = 0;
if ((mpt3sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0,
MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) {
ioc_err(ioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__); return -ENXIO;
}
ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { /* For HBA, vSES doesn't return HBA SAS address. Instead return * vSES's sas address.
*/ if ((handle <= ioc->sas_hba.num_phys) &&
(!(le32_to_cpu(sas_device_pg0.DeviceInfo) &
MPI2_SAS_DEVICE_INFO_SEP)))
*sas_address = ioc->sas_hba.sas_address; else
*sas_address = le64_to_cpu(sas_device_pg0.SASAddress); return 0;
}
/* we hit this because the given parent handle doesn't exist */ if (ioc_status == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) return -ENXIO;
/* else error case */
ioc_err(ioc, "handle(0x%04x), ioc_status(0x%04x), failure at %s:%d/%s()!\n",
handle, ioc_status, __FILE__, __LINE__, __func__); return -EIO;
}
/** * _scsih_determine_boot_device - determine boot device. * @ioc: per adapter object * @device: sas_device or pcie_device object * @channel: SAS or PCIe channel * * Determines whether this device should be first reported device to * to scsi-ml or sas transport, this purpose is for persistent boot device. * There are primary, alternate, and current entries in bios page 2. The order * priority is primary, alternate, then current. This routine saves * the corresponding device object. * The saved data to be used later in _scsih_probe_boot_devices().
*/ staticvoid
_scsih_determine_boot_device(struct MPT3SAS_ADAPTER *ioc, void *device,
u32 channel)
{ struct _sas_device *sas_device; struct _pcie_device *pcie_device; struct _raid_device *raid_device;
u64 sas_address;
u64 device_name;
u64 enclosure_logical_id;
u16 slot;
/* only process this function when driver loads */ if (!ioc->is_driver_loading) return;
/* no Bios, return immediately */ if (!ioc->bios_pg3.BiosVersion) return;
ret = tgt_priv->pcie_dev; if (ret)
pcie_device_get(ret);
return ret;
}
/** * mpt3sas_get_pdev_from_target - pcie device search * @ioc: per adapter object * @tgt_priv: starget private object * * Context: This function will acquire ioc->pcie_device_lock and will release * before returning the pcie_device object. * * This searches for pcie_device from target, then return pcie_device object.
*/ staticstruct _pcie_device *
mpt3sas_get_pdev_from_target(struct MPT3SAS_ADAPTER *ioc, struct MPT3SAS_TARGET *tgt_priv)
{ struct _pcie_device *ret; unsignedlong flags;
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
ret = __mpt3sas_get_pdev_from_target(ioc, tgt_priv);
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags);
return ret;
}
/** * __mpt3sas_get_sdev_by_rphy - sas device search * @ioc: per adapter object * @rphy: sas_rphy pointer * * Context: This function will acquire ioc->sas_device_lock and will release * before returning the sas_device object. * * This searches for sas_device from rphy object * then return sas_device object.
*/ struct _sas_device *
__mpt3sas_get_sdev_by_rphy(struct MPT3SAS_ADAPTER *ioc, struct sas_rphy *rphy)
{ struct _sas_device *sas_device;
/** * __mpt3sas_get_sdev_by_addr - get _sas_device object corresponding to provided * sas address from sas_device_list list * @ioc: per adapter object * @sas_address: device sas address * @port: port number * * Search for _sas_device object corresponding to provided sas address, * if available return _sas_device object address otherwise return NULL.
*/ struct _sas_device *
__mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
u64 sas_address, struct hba_port *port)
{ struct _sas_device *sas_device;
if (!port) return NULL;
assert_spin_locked(&ioc->sas_device_lock);
list_for_each_entry(sas_device, &ioc->sas_device_list, list) { if (sas_device->sas_address != sas_address) continue; if (sas_device->port != port) continue;
sas_device_get(sas_device); return sas_device;
}
list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) { if (sas_device->sas_address != sas_address) continue; if (sas_device->port != port) continue;
sas_device_get(sas_device); return sas_device;
}
return NULL;
}
/** * mpt3sas_get_sdev_by_addr - sas device search * @ioc: per adapter object * @sas_address: sas address * @port: hba port entry * Context: Calling function should acquire ioc->sas_device_lock * * This searches for sas_device based on sas_address & port number, * then return sas_device object.
*/ struct _sas_device *
mpt3sas_get_sdev_by_addr(struct MPT3SAS_ADAPTER *ioc,
u64 sas_address, struct hba_port *port)
{ struct _sas_device *sas_device; unsignedlong flags;
/** * _scsih_sas_device_remove - remove sas_device from list. * @ioc: per adapter object * @sas_device: the sas_device object * Context: This function will acquire ioc->sas_device_lock. * * If sas_device is on the list, remove it and decrement its reference count.
*/ staticvoid
_scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, struct _sas_device *sas_device)
{ unsignedlong flags;
if (!sas_device) return;
ioc_info(ioc, "removing handle(0x%04x), sas_addr(0x%016llx)\n",
sas_device->handle, (u64)sas_device->sas_address);
/* * The lock serializes access to the list, but we still need to verify * that nobody removed the entry while we were waiting on the lock.
*/
spin_lock_irqsave(&ioc->sas_device_lock, flags); if (!list_empty(&sas_device->list)) {
list_del_init(&sas_device->list);
sas_device_put(sas_device);
}
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
}
/** * _scsih_sas_device_add - insert sas_device to the list. * @ioc: per adapter object * @sas_device: the sas_device object * Context: This function will acquire ioc->sas_device_lock. * * Adding new object to the ioc->sas_device_list.
*/ staticvoid
_scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, struct _sas_device *sas_device)
{ unsignedlong flags;
if (ioc->hide_drives) {
clear_bit(sas_device->handle, ioc->pend_os_device_add); return;
}
if (!mpt3sas_transport_port_add(ioc, sas_device->handle,
sas_device->sas_address_parent, sas_device->port)) {
_scsih_sas_device_remove(ioc, sas_device);
} elseif (!sas_device->starget) { /* * When asyn scanning is enabled, its not possible to remove * devices while scanning is turned on due to an oops in * scsi_sysfs_add_sdev()->add_device()->sysfs_addrm_start()
*/ if (!ioc->is_driver_loading) {
mpt3sas_transport_port_remove(ioc,
sas_device->sas_address,
sas_device->sas_address_parent,
sas_device->port);
_scsih_sas_device_remove(ioc, sas_device);
}
} else
clear_bit(sas_device->handle, ioc->pend_os_device_add);
}
/** * _scsih_sas_device_init_add - insert sas_device to the list. * @ioc: per adapter object * @sas_device: the sas_device object * Context: This function will acquire ioc->sas_device_lock. * * Adding new object at driver load time to the ioc->sas_device_init_list.
*/ staticvoid
_scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, struct _sas_device *sas_device)
{ unsignedlong flags;
/** * mpt3sas_get_pdev_by_wwid - pcie device search * @ioc: per adapter object * @wwid: wwid * * Context: This function will acquire ioc->pcie_device_lock and will release * before returning the pcie_device object. * * This searches for pcie_device based on wwid, then return pcie_device object.
*/ staticstruct _pcie_device *
mpt3sas_get_pdev_by_wwid(struct MPT3SAS_ADAPTER *ioc, u64 wwid)
{ struct _pcie_device *pcie_device; unsignedlong flags;
/** * mpt3sas_get_pdev_by_handle - pcie device search * @ioc: per adapter object * @handle: Firmware device handle * * Context: This function will acquire ioc->pcie_device_lock and will release * before returning the pcie_device object. * * This searches for pcie_device based on handle, then return pcie_device * object.
*/ struct _pcie_device *
mpt3sas_get_pdev_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{ struct _pcie_device *pcie_device; unsignedlong flags;
/** * _scsih_set_nvme_max_shutdown_latency - Update max_shutdown_latency. * @ioc: per adapter object * Context: This function will acquire ioc->pcie_device_lock * * Update ioc->max_shutdown_latency to that NVMe drives RTD3 Entry Latency * which has reported maximum among all available NVMe drives. * Minimum max_shutdown_latency will be six seconds.
*/ staticvoid
_scsih_set_nvme_max_shutdown_latency(struct MPT3SAS_ADAPTER *ioc)
{ struct _pcie_device *pcie_device; unsignedlong flags;
u16 shutdown_latency = IO_UNIT_CONTROL_SHUTDOWN_TIMEOUT;
/** * _scsih_pcie_device_remove - remove pcie_device from list. * @ioc: per adapter object * @pcie_device: the pcie_device object * Context: This function will acquire ioc->pcie_device_lock. * * If pcie_device is on the list, remove it and decrement its reference count.
*/ staticvoid
_scsih_pcie_device_remove(struct MPT3SAS_ADAPTER *ioc, struct _pcie_device *pcie_device)
{ unsignedlong flags; int was_on_pcie_device_list = 0;
u8 update_latency = 0;
spin_lock_irqsave(&ioc->pcie_device_lock, flags); if (!list_empty(&pcie_device->list)) {
list_del_init(&pcie_device->list);
was_on_pcie_device_list = 1;
} if (pcie_device->shutdown_latency == ioc->max_shutdown_latency)
update_latency = 1;
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); if (was_on_pcie_device_list) {
kfree(pcie_device->serial_number);
pcie_device_put(pcie_device);
}
/* * This device's RTD3 Entry Latency matches IOC's * max_shutdown_latency. Recalculate IOC's max_shutdown_latency * from the available drives as current drive is getting removed.
*/ if (update_latency)
_scsih_set_nvme_max_shutdown_latency(ioc);
}
spin_lock_irqsave(&ioc->pcie_device_lock, flags);
pcie_device = __mpt3sas_get_pdev_by_handle(ioc, handle); if (pcie_device) { if (!list_empty(&pcie_device->list)) {
list_del_init(&pcie_device->list);
was_on_pcie_device_list = 1;
pcie_device_put(pcie_device);
} if (pcie_device->shutdown_latency == ioc->max_shutdown_latency)
update_latency = 1;
}
spin_unlock_irqrestore(&ioc->pcie_device_lock, flags); if (was_on_pcie_device_list) {
_scsih_pcie_device_remove_from_sml(ioc, pcie_device);
pcie_device_put(pcie_device);
}
/* * This device's RTD3 Entry Latency matches IOC's * max_shutdown_latency. Recalculate IOC's max_shutdown_latency * from the available drives as current drive is getting removed.
*/ if (update_latency)
_scsih_set_nvme_max_shutdown_latency(ioc);
}
/** * _scsih_pcie_device_add - add pcie_device object * @ioc: per adapter object * @pcie_device: pcie_device object * * This is added to the pcie_device_list link list.
*/ staticvoid
_scsih_pcie_device_add(struct MPT3SAS_ADAPTER *ioc, struct _pcie_device *pcie_device)
{ unsignedlong flags;
if (pcie_device->access_status ==
MPI26_PCIEDEV0_ASTATUS_DEVICE_BLOCKED) {
clear_bit(pcie_device->handle, ioc->pend_os_device_add); return;
} if (scsi_add_device(ioc->shost, PCIE_CHANNEL, pcie_device->id, 0)) {
_scsih_pcie_device_remove(ioc, pcie_device);
} elseif (!pcie_device->starget) { if (!ioc->is_driver_loading) { /*TODO-- Need to find out whether this condition will occur or not*/
clear_bit(pcie_device->handle, ioc->pend_os_device_add);
}
} else
clear_bit(pcie_device->handle, ioc->pend_os_device_add);
}
/* * _scsih_pcie_device_init_add - insert pcie_device to the init list. * @ioc: per adapter object * @pcie_device: the pcie_device object * Context: This function will acquire ioc->pcie_device_lock. * * Adding new object at driver load time to the ioc->pcie_device_init_list.
*/ staticvoid
_scsih_pcie_device_init_add(struct MPT3SAS_ADAPTER *ioc, struct _pcie_device *pcie_device)
{ unsignedlong flags;
/** * mpt3sas_scsih_expander_find_by_handle - expander device search * @ioc: per adapter object * @handle: expander handle (assigned by firmware) * Context: Calling function should acquire ioc->sas_device_lock * * This searches for expander device based on handle, then returns the * sas_node object.
*/ struct _sas_node *
mpt3sas_scsih_expander_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{ struct _sas_node *sas_expander, *r;
r = NULL;
list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { if (sas_expander->handle != handle) continue;
r = sas_expander; goto out;
}
out: return r;
}
/** * mpt3sas_scsih_enclosure_find_by_handle - exclosure device search * @ioc: per adapter object * @handle: enclosure handle (assigned by firmware) * Context: Calling function should acquire ioc->sas_device_lock * * This searches for enclosure device based on handle, then returns the * enclosure object.
*/ staticstruct _enclosure_node *
mpt3sas_scsih_enclosure_find_by_handle(struct MPT3SAS_ADAPTER *ioc, u16 handle)
{ struct _enclosure_node *enclosure_dev, *r;
r = NULL;
list_for_each_entry(enclosure_dev, &ioc->enclosure_list, list) { if (le16_to_cpu(enclosure_dev->pg0.EnclosureHandle) != handle) continue;
r = enclosure_dev; goto out;
}
out: return r;
} /** * mpt3sas_scsih_expander_find_by_sas_address - expander device search * @ioc: per adapter object * @sas_address: sas address * @port: hba port entry * Context: Calling function should acquire ioc->sas_node_lock. * * This searches for expander device based on sas_address & port number, * then returns the sas_node object.
*/ struct _sas_node *
mpt3sas_scsih_expander_find_by_sas_address(struct MPT3SAS_ADAPTER *ioc,
u64 sas_address, struct hba_port *port)
{ struct _sas_node *sas_expander, *r = NULL;
if (!port) return r;
list_for_each_entry(sas_expander, &ioc->sas_expander_list, list) { if (sas_expander->sas_address != sas_address) continue; if (sas_expander->port != port) continue;
r = sas_expander; goto out;
}
out: return r;
}
/** * _scsih_expander_node_add - insert expander device to the list. * @ioc: per adapter object * @sas_expander: the sas_device object * Context: This function will acquire ioc->sas_node_lock. * * Adding new object to the ioc->sas_expander_list.
*/ staticvoid
_scsih_expander_node_add(struct MPT3SAS_ADAPTER *ioc, struct _sas_node *sas_expander)
{ unsignedlong flags;
/** * _scsih_is_end_device - determines if device is an end device * @device_info: bitfield providing information about the device. * Context: none * * Return: 1 if end device.
*/ staticint
_scsih_is_end_device(u32 device_info)
{ if (device_info & MPI2_SAS_DEVICE_INFO_END_DEVICE &&
((device_info & MPI2_SAS_DEVICE_INFO_SSP_TARGET) |
(device_info & MPI2_SAS_DEVICE_INFO_STP_TARGET) |
(device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE))) return 1; else return 0;
}
/** * _scsih_is_nvme_pciescsi_device - determines if * device is an pcie nvme/scsi device * @device_info: bitfield providing information about the device. * Context: none * * Returns 1 if device is pcie device type nvme/scsi.
*/ staticint
_scsih_is_nvme_pciescsi_device(u32 device_info)
{ if (((device_info & MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE)
== MPI26_PCIE_DEVINFO_NVME) ||
((device_info & MPI26_PCIE_DEVINFO_MASK_DEVICE_TYPE)
== MPI26_PCIE_DEVINFO_SCSI)) return 1; else return 0;
}
/** * _scsih_scsi_lookup_find_by_target - search for matching channel:id * @ioc: per adapter object * @id: target id * @channel: channel * Context: This function will acquire ioc->scsi_lookup_lock. * * This will search for a matching channel:id in the scsi_lookup array, * returning 1 if found.
*/ static u8
_scsih_scsi_lookup_find_by_target(struct MPT3SAS_ADAPTER *ioc, int id, int channel)
{ int smid; struct scsi_cmnd *scmd;
for (smid = 1;
smid <= ioc->shost->can_queue; smid++) {
scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid); if (!scmd) continue; if (scmd->device->id == id &&
scmd->device->channel == channel) return 1;
} return 0;
}
/** * _scsih_scsi_lookup_find_by_lun - search for matching channel:id:lun * @ioc: per adapter object * @id: target id * @lun: lun number * @channel: channel * Context: This function will acquire ioc->scsi_lookup_lock. * * This will search for a matching channel:id:lun in the scsi_lookup array, * returning 1 if found.
*/ static u8
_scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id, unsignedint lun, int channel)
{ int smid; struct scsi_cmnd *scmd;
for (smid = 1; smid <= ioc->shost->can_queue; smid++) {
scmd = mpt3sas_scsih_scsi_lookup_get(ioc, smid); if (!scmd) continue; if (scmd->device->id == id &&
scmd->device->channel == channel &&
scmd->device->lun == lun) return 1;
} return 0;
}
/** * mpt3sas_scsih_scsi_lookup_get - returns scmd entry * @ioc: per adapter object * @smid: system request message index * * Return: the smid stored scmd pointer. * Then will dereference the stored scmd pointer.
*/ struct scsi_cmnd *
mpt3sas_scsih_scsi_lookup_get(struct MPT3SAS_ADAPTER *ioc, u16 smid)
{ struct scsi_cmnd *scmd = NULL; struct scsiio_tracker *st;
Mpi25SCSIIORequest_t *mpi_request;
u16 tag = smid - 1;
/* * If SCSI IO request is outstanding at driver level then * DevHandle filed must be non-zero. If DevHandle is zero * then it means that this smid is free at driver level, * so return NULL.
*/ if (!mpi_request->DevHandle) return scmd;
scmd = scsi_host_find_tag(ioc->shost, unique_tag); if (scmd) {
st = scsi_cmd_priv(scmd); if (st->cb_idx == 0xFF || st->smid == 0)
scmd = NULL;
}
} return scmd;
}
/* * raid transport support - * Enabled for SLES11 and newer, in older kernels the driver will panic when * unloading the driver followed by a load - I believe that the subroutine * raid_class_release() is not cleaning up properly.
*/
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.