/** * mpi3mr_post_transport_req - Issue transport requests and wait * @mrioc: Adapter instance reference * @request: Properly populated MPI3 request * @request_sz: Size of the MPI3 request * @reply: Pointer to return MPI3 reply * @reply_sz: Size of the MPI3 reply buffer * @timeout: Timeout in seconds * @ioc_status: Pointer to return ioc status * * A generic function for posting MPI3 requests from the SAS * transport layer that uses transport command infrastructure. * This blocks for the completion of request for timeout seconds * and if the request times out this function faults the * controller with proper reason code. * * On successful completion of the request this function returns * appropriate ioc status from the firmware back to the caller. * * Return: 0 on success, non-zero on failure.
*/ staticint mpi3mr_post_transport_req(struct mpi3mr_ioc *mrioc, void *request,
u16 request_sz, void *reply, u16 reply_sz, int timeout,
u16 *ioc_status)
{ int retval = 0;
mutex_lock(&mrioc->transport_cmds.mutex); if (mrioc->transport_cmds.state & MPI3MR_CMD_PENDING) {
retval = -1;
ioc_err(mrioc, "sending transport request failed due to command in use\n");
mutex_unlock(&mrioc->transport_cmds.mutex); goto out;
}
mrioc->transport_cmds.state = MPI3MR_CMD_PENDING;
mrioc->transport_cmds.is_waiting = 1;
mrioc->transport_cmds.callback = NULL;
mrioc->transport_cmds.ioc_status = 0;
mrioc->transport_cmds.ioc_loginfo = 0;
init_completion(&mrioc->transport_cmds.done);
dprint_cfg_info(mrioc, "posting transport request\n"); if (mrioc->logging_level & MPI3_DEBUG_TRANSPORT_INFO)
dprint_dump(request, request_sz, "transport_req");
retval = mpi3mr_admin_request_post(mrioc, request, request_sz, 1); if (retval) {
ioc_err(mrioc, "posting transport request failed\n"); goto out_unlock;
}
wait_for_completion_timeout(&mrioc->transport_cmds.done,
(timeout * HZ)); if (!(mrioc->transport_cmds.state & MPI3MR_CMD_COMPLETE)) {
mpi3mr_check_rh_fault_ioc(mrioc,
MPI3MR_RESET_FROM_SAS_TRANSPORT_TIMEOUT);
ioc_err(mrioc, "transport request timed out\n");
retval = -1; goto out_unlock;
}
*ioc_status = mrioc->transport_cmds.ioc_status &
MPI3_IOCSTATUS_STATUS_MASK; if ((*ioc_status) != MPI3_IOCSTATUS_SUCCESS)
dprint_transport_err(mrioc, "transport request returned with ioc_status(0x%04x), log_info(0x%08x)\n",
*ioc_status, mrioc->transport_cmds.ioc_loginfo);
if ((reply) && (mrioc->transport_cmds.state & MPI3MR_CMD_REPLY_VALID))
memcpy((u8 *)reply, mrioc->transport_cmds.reply, reply_sz);
out: if (data_out)
dma_free_coherent(&mrioc->pdev->dev, data_out_sz + data_in_sz,
data_out, data_out_dma);
return rc;
}
/** * __mpi3mr_expander_find_by_handle - expander search by handle * @mrioc: Adapter instance reference * @handle: Firmware device handle of the expander * * Context: The caller should acquire sas_node_lock * * This searches for expander device based on handle, then * returns the sas_node object. * * Return: Expander sas_node object reference or NULL
*/ struct mpi3mr_sas_node *__mpi3mr_expander_find_by_handle(struct mpi3mr_ioc
*mrioc, u16 handle)
{ struct mpi3mr_sas_node *sas_expander, *r;
r = NULL;
list_for_each_entry(sas_expander, &mrioc->sas_expander_list, list) { if (sas_expander->handle != handle) continue;
r = sas_expander; goto out;
}
out: return r;
}
/** * mpi3mr_is_expander_device - if device is an expander * @device_info: Bitfield providing information about the device * * Return: 1 if the device is expander device, else 0.
*/
u8 mpi3mr_is_expander_device(u16 device_info)
{ if ((device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) ==
MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER) return 1; else return 0;
}
/** * mpi3mr_get_sas_address - retrieve sas_address for handle * @mrioc: Adapter instance reference * @handle: Firmware device handle * @sas_address: Address to hold sas address * * This function issues device page0 read for a given device * handle and gets the SAS address and return it back * * Return: 0 for success, non-zero for failure
*/ staticint mpi3mr_get_sas_address(struct mpi3mr_ioc *mrioc, u16 handle,
u64 *sas_address)
{ struct mpi3_device_page0 dev_pg0;
u16 ioc_status; struct mpi3_device0_sas_sata_format *sasinf;
/** * mpi3mr_get_tgtdev_by_addr - target device search * @mrioc: Adapter instance reference * @sas_address: SAS address of the device * @hba_port: HBA port entry * * This searches for target device from sas address and hba port * pointer then return mpi3mr_tgt_dev object. * * Context: This function will acquire tgtdev_lock and will * release before returning the mpi3mr_tgt_dev object. * * Return: Valid tget_dev or NULL
*/ staticstruct mpi3mr_tgt_dev *mpi3mr_get_tgtdev_by_addr(struct mpi3mr_ioc *mrioc,
u64 sas_address, struct mpi3mr_hba_port *hba_port)
{ struct mpi3mr_tgt_dev *tgtdev = NULL; unsignedlong flags;
/** * mpi3mr_remove_device_by_sas_address - remove the device * @mrioc: Adapter instance reference * @sas_address: SAS address of the device * @hba_port: HBA port entry * * This searches for target device using sas address and hba * port pointer then removes it from the OS. * * Return: None
*/ staticvoid mpi3mr_remove_device_by_sas_address(struct mpi3mr_ioc *mrioc,
u64 sas_address, struct mpi3mr_hba_port *hba_port)
{ struct mpi3mr_tgt_dev *tgtdev = NULL; unsignedlong flags;
u8 was_on_tgtdev_list = 0;
if (!hba_port) return;
spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
tgtdev = __mpi3mr_get_tgtdev_by_addr(mrioc,
sas_address, hba_port); if (tgtdev) { if (!list_empty(&tgtdev->list)) {
was_on_tgtdev_list = 1; if (tgtdev->state == MPI3MR_DEV_REMOVE_HS_STARTED) {
list_del_init(&tgtdev->list);
mpi3mr_tgtdev_put(tgtdev);
}
}
}
spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags); if (was_on_tgtdev_list) { if (tgtdev->host_exposed)
mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev);
mpi3mr_tgtdev_put(tgtdev);
}
}
/** * __mpi3mr_get_tgtdev_by_addr_and_rphy - target device search * @mrioc: Adapter instance reference * @sas_address: SAS address of the device * @rphy: SAS transport layer rphy object * * This searches for target device from sas address and rphy * pointer then return mpi3mr_tgt_dev object. * * Return: Valid tget_dev or NULL
*/ struct mpi3mr_tgt_dev *__mpi3mr_get_tgtdev_by_addr_and_rphy( struct mpi3mr_ioc *mrioc, u64 sas_address, struct sas_rphy *rphy)
{ struct mpi3mr_tgt_dev *tgtdev;
/** * __mpi3mr_sas_node_find_by_sas_address - sas node search * @mrioc: Adapter instance reference * @sas_address: SAS address of expander or sas host * @hba_port: HBA port entry * Context: Caller should acquire mrioc->sas_node_lock. * * If the SAS address indicates the device is direct attached to * the controller (controller's SAS address) then the SAS node * associated with the controller is returned back else the SAS * address and hba port are used to identify the exact expander * and the associated sas_node object is returned. If there is * no match NULL is returned. * * Return: A valid SAS node or NULL. *
*/ staticstruct mpi3mr_sas_node *__mpi3mr_sas_node_find_by_sas_address( struct mpi3mr_ioc *mrioc, u64 sas_address, struct mpi3mr_hba_port *hba_port)
{
/** * mpi3mr_convert_phy_link_rate - * @link_rate: link rate as defined in the MPI header * * Convert link_rate from mpi format into sas_transport layer * form. * * Return: A valid SAS transport layer defined link rate
*/ staticenum sas_linkrate mpi3mr_convert_phy_link_rate(u8 link_rate)
{ enum sas_linkrate rc;
switch (link_rate) { case MPI3_SAS_NEG_LINK_RATE_1_5:
rc = SAS_LINK_RATE_1_5_GBPS; break; case MPI3_SAS_NEG_LINK_RATE_3_0:
rc = SAS_LINK_RATE_3_0_GBPS; break; case MPI3_SAS_NEG_LINK_RATE_6_0:
rc = SAS_LINK_RATE_6_0_GBPS; break; case MPI3_SAS_NEG_LINK_RATE_12_0:
rc = SAS_LINK_RATE_12_0_GBPS; break; case MPI3_SAS_NEG_LINK_RATE_22_5:
rc = SAS_LINK_RATE_22_5_GBPS; break; case MPI3_SAS_NEG_LINK_RATE_PHY_DISABLED:
rc = SAS_PHY_DISABLED; break; case MPI3_SAS_NEG_LINK_RATE_NEGOTIATION_FAILED:
rc = SAS_LINK_RATE_FAILED; break; case MPI3_SAS_NEG_LINK_RATE_PORT_SELECTOR:
rc = SAS_SATA_PORT_SELECTOR; break; case MPI3_SAS_NEG_LINK_RATE_SMP_RESET_IN_PROGRESS:
rc = SAS_PHY_RESET_IN_PROGRESS; break; case MPI3_SAS_NEG_LINK_RATE_SATA_OOB_COMPLETE: case MPI3_SAS_NEG_LINK_RATE_UNKNOWN_LINK_RATE: default:
rc = SAS_LINK_RATE_UNKNOWN; break;
} return rc;
}
/** * mpi3mr_delete_sas_phy - Remove a single phy from port * @mrioc: Adapter instance reference * @mr_sas_port: Internal Port object * @mr_sas_phy: Internal Phy object * @host_node: Flag to indicate this is a host_node * * Return: None.
*/ staticvoid mpi3mr_delete_sas_phy(struct mpi3mr_ioc *mrioc, struct mpi3mr_sas_port *mr_sas_port, struct mpi3mr_sas_phy *mr_sas_phy, u8 host_node)
{
u64 sas_address = mr_sas_port->remote_identify.sas_address;
/** * mpi3mr_sas_port_sanity_check - sanity check while adding port * @mrioc: Adapter instance reference * @mr_sas_node: Internal sas node object (expander or host) * @sas_address: SAS address of device/expander * @hba_port: HBA port entry * * Verifies whether the Phys attached to a device with the given * SAS address already belongs to an existing sas port if so * will remove those phys from the sas port * * Return: None.
*/ staticvoid mpi3mr_sas_port_sanity_check(struct mpi3mr_ioc *mrioc, struct mpi3mr_sas_node *mr_sas_node, u64 sas_address, struct mpi3mr_hba_port *hba_port)
{ int i;
for (i = 0; i < mr_sas_node->num_phys; i++) { if ((mr_sas_node->phy[i].remote_identify.sas_address !=
sas_address) || (mr_sas_node->phy[i].hba_port != hba_port)) continue; if (mr_sas_node->phy[i].phy_belongs_to_port == 1)
mpi3mr_del_phy_from_an_existing_port(mrioc,
mr_sas_node, &mr_sas_node->phy[i]);
}
}
/** * mpi3mr_set_identify - set identify for phys and end devices * @mrioc: Adapter instance reference * @handle: Firmware device handle * @identify: SAS transport layer's identify info * * Populates sas identify info for a specific device. * * Return: 0 for success, non-zero for failure.
*/ staticint mpi3mr_set_identify(struct mpi3mr_ioc *mrioc, u16 handle, struct sas_identify *identify)
{
/* phy number of the parent device this device is linked to */
identify->phy_identifier = sasinf->phy_num;
/* device_type */ switch (device_info & MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_MASK) { case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_NO_DEVICE:
identify->device_type = SAS_PHY_UNUSED; break; case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_END_DEVICE:
identify->device_type = SAS_END_DEVICE; break; case MPI3_SAS_DEVICE_INFO_DEVICE_TYPE_EXPANDER:
identify->device_type = SAS_EDGE_EXPANDER_DEVICE; break;
}
/* initiator_port_protocols */ if (device_info & MPI3_SAS_DEVICE_INFO_SSP_INITIATOR)
identify->initiator_port_protocols |= SAS_PROTOCOL_SSP; /* MPI3.0 doesn't have define for SATA INIT so setting both here*/ if (device_info & MPI3_SAS_DEVICE_INFO_STP_INITIATOR)
identify->initiator_port_protocols |= (SAS_PROTOCOL_STP |
SAS_PROTOCOL_SATA); if (device_info & MPI3_SAS_DEVICE_INFO_SMP_INITIATOR)
identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
/* target_port_protocols */ if (device_info & MPI3_SAS_DEVICE_INFO_SSP_TARGET)
identify->target_port_protocols |= SAS_PROTOCOL_SSP; /* MPI3.0 doesn't have define for STP Target so setting both here*/ if (device_info & MPI3_SAS_DEVICE_INFO_STP_SATA_TARGET)
identify->target_port_protocols |= (SAS_PROTOCOL_STP |
SAS_PROTOCOL_SATA); if (device_info & MPI3_SAS_DEVICE_INFO_SMP_TARGET)
identify->target_port_protocols |= SAS_PROTOCOL_SMP; return 0;
}
/** * mpi3mr_add_host_phy - report sas_host phy to SAS transport * @mrioc: Adapter instance reference * @mr_sas_phy: Internal Phy object * @phy_pg0: SAS phy page 0 * @parent_dev: Prent device class object * * Return: 0 for success, non-zero for failure.
*/ staticint mpi3mr_add_host_phy(struct mpi3mr_ioc *mrioc, struct mpi3mr_sas_phy *mr_sas_phy, struct mpi3_sas_phy_page0 phy_pg0, struct device *parent_dev)
{ struct sas_phy *phy; int phy_index = mr_sas_phy->phy_id;
/** * mpi3mr_alloc_hba_port - alloc hba port object * @mrioc: Adapter instance reference * @port_id: Port number * * Alloc memory for hba port object.
*/ staticstruct mpi3mr_hba_port *
mpi3mr_alloc_hba_port(struct mpi3mr_ioc *mrioc, u16 port_id)
{ struct mpi3mr_hba_port *hba_port;
hba_port = kzalloc(sizeof(struct mpi3mr_hba_port),
GFP_KERNEL); if (!hba_port) return NULL;
hba_port->port_id = port_id;
ioc_info(mrioc, "hba_port entry: %p, port: %d is added to hba_port list\n",
hba_port, hba_port->port_id); if (mrioc->reset_in_progress ||
mrioc->pci_err_recovery)
hba_port->flags = MPI3MR_HBA_PORT_FLAG_NEW;
list_add_tail(&hba_port->list, &mrioc->hba_port_table_list); return hba_port;
}
/** * mpi3mr_get_hba_port_by_id - find hba port by id * @mrioc: Adapter instance reference * @port_id: Port ID to search * * Return: mpi3mr_hba_port reference for the matched port
*/
/** * mpi3mr_sas_host_refresh - refreshing sas host object contents * @mrioc: Adapter instance reference * * This function refreshes the controllers phy information and * updates the SAS transport layer with updated information, * this is executed for each device addition or device info * change events * * Return: None.
*/ void mpi3mr_sas_host_refresh(struct mpi3mr_ioc *mrioc)
{ int i;
u8 link_rate;
u16 sz, port_id, attached_handle; struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL;
dprint_transport_info(mrioc, "updating handles for sas_host(0x%016llx)\n",
(unsignedlonglong)mrioc->sas_hba.sas_address);
/** * mpi3mr_sas_host_add - create sas host object * @mrioc: Adapter instance reference * * This function creates the controllers phy information and * updates the SAS transport layer with updated information, * this is executed for first device addition or device info * change event. * * Return: None.
*/ void mpi3mr_sas_host_add(struct mpi3mr_ioc *mrioc)
{ int i;
u16 sz, num_phys = 1, port_id, ioc_status; struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL; struct mpi3_sas_phy_page0 phy_pg0; struct mpi3_device_page0 dev_pg0; struct mpi3_enclosure_page0 encl_pg0; struct mpi3_device0_sas_sata_format *sasinf;
if (mrioc->sas_hba.enclosure_handle) { if (!(mpi3mr_cfg_get_enclosure_pg0(mrioc, &ioc_status,
&encl_pg0, sizeof(encl_pg0),
MPI3_ENCLOS_PGAD_FORM_HANDLE,
mrioc->sas_hba.enclosure_handle)) &&
(ioc_status == MPI3_IOCSTATUS_SUCCESS))
mrioc->sas_hba.enclosure_logical_id =
le64_to_cpu(encl_pg0.enclosure_logical_id);
}
out:
kfree(sas_io_unit_pg0);
}
/** * mpi3mr_sas_port_add - Expose the SAS device to the SAS TL * @mrioc: Adapter instance reference * @handle: Firmware device handle of the attached device * @sas_address_parent: sas address of parent expander or host * @hba_port: HBA port entry * * This function creates a new sas port object for the given end * device matching sas address and hba_port and adds it to the * sas_node's sas_port_list and expose the attached sas device * to the SAS transport layer through sas_rphy_add. * * Returns a valid mpi3mr_sas_port reference or NULL.
*/ staticstruct mpi3mr_sas_port *mpi3mr_sas_port_add(struct mpi3mr_ioc *mrioc,
u16 handle, u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
{ struct mpi3mr_sas_phy *mr_sas_phy, *next; struct mpi3mr_sas_port *mr_sas_port; unsignedlong flags; struct mpi3mr_sas_node *mr_sas_node; struct sas_rphy *rphy; struct mpi3mr_tgt_dev *tgtdev = NULL; int i; struct sas_port *port;
if (!hba_port) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__); return NULL;
}
mr_sas_port = kzalloc(sizeof(struct mpi3mr_sas_port), GFP_KERNEL); if (!mr_sas_port) return NULL;
if (mr_sas_node->host_node && mr_sas_node->num_phys >= sizeof(mr_sas_port->phy_mask) * 8)
ioc_info(mrioc, "max port count %u could be too high\n",
mr_sas_node->num_phys);
for (i = 0; i < mr_sas_node->num_phys; i++) { if ((mr_sas_node->phy[i].remote_identify.sas_address !=
mr_sas_port->remote_identify.sas_address) ||
(mr_sas_node->phy[i].hba_port != hba_port)) continue;
if (mr_sas_node->host_node && (i >= sizeof(mr_sas_port->phy_mask) * 8)) {
ioc_warn(mrioc, "skipping port %u, max allowed value is %zu\n",
i, sizeof(mr_sas_port->phy_mask) * 8); goto out_fail;
}
list_add_tail(&mr_sas_node->phy[i].port_siblings,
&mr_sas_port->phy_list);
mr_sas_port->num_phys++; if (mr_sas_node->host_node)
mr_sas_port->phy_mask |= (1 << i);
}
if (!mr_sas_port->num_phys) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__); goto out_fail;
}
if (mr_sas_node->host_node)
mr_sas_port->lowest_phy = ffs(mr_sas_port->phy_mask) - 1;
if (mr_sas_port->remote_identify.device_type == SAS_END_DEVICE) {
tgtdev = mpi3mr_get_tgtdev_by_addr(mrioc,
mr_sas_port->remote_identify.sas_address,
mr_sas_port->hba_port);
if (!tgtdev) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__); goto out_fail;
}
tgtdev->dev_spec.sas_sata_inf.pend_sas_rphy_add = 1;
}
if (!mr_sas_node->parent_dev) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__); goto out_fail;
}
port = sas_port_alloc_num(mr_sas_node->parent_dev); if ((sas_port_add(port))) {
ioc_err(mrioc, "failure at %s:%d/%s()!\n",
__FILE__, __LINE__, __func__); goto out_fail;
}
/** * mpi3mr_sas_port_remove - remove port from the list * @mrioc: Adapter instance reference * @sas_address: SAS address of attached device * @sas_address_parent: SAS address of parent expander or host * @hba_port: HBA port entry * * Removing object and freeing associated memory from the * sas_port_list. * * Return: None
*/ staticvoid mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address,
u64 sas_address_parent, struct mpi3mr_hba_port *hba_port)
{ int i; unsignedlong flags; struct mpi3mr_sas_port *mr_sas_port, *next; struct mpi3mr_sas_node *mr_sas_node;
u8 found = 0; struct mpi3mr_sas_phy *mr_sas_phy, *next_phy; struct mpi3mr_hba_port *srch_port, *hba_port_next = NULL;
if (!hba_port) return;
spin_lock_irqsave(&mrioc->sas_node_lock, flags);
mr_sas_node = __mpi3mr_sas_node_find_by_sas_address(mrioc,
sas_address_parent, hba_port); if (!mr_sas_node) {
spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); return;
}
list_for_each_entry_safe(mr_sas_port, next, &mr_sas_node->sas_port_list,
port_list) { if (mr_sas_port->remote_identify.sas_address != sas_address) continue; if (mr_sas_port->hba_port != hba_port) continue;
found = 1;
list_del(&mr_sas_port->port_list); goto out;
}
out: if (!found) {
spin_unlock_irqrestore(&mrioc->sas_node_lock, flags); return;
}
if (mr_sas_node->host_node) {
list_for_each_entry_safe(srch_port, hba_port_next,
&mrioc->hba_port_table_list, list) { if (srch_port != hba_port) continue;
ioc_info(mrioc, "removing hba_port entry: %p port: %d from hba_port list\n",
srch_port, srch_port->port_id);
list_del(&hba_port->list);
kfree(hba_port); break;
}
}
for (i = 0; i < mr_sas_node->num_phys; i++) { if (mr_sas_node->phy[i].remote_identify.sas_address ==
sas_address)
memset(&mr_sas_node->phy[i].remote_identify, 0, sizeof(struct sas_identify));
}
if (mrioc->current_event) {
mrioc->current_event->pending_at_sml = 0; if (mrioc->current_event->discard)
mpi3mr_print_device_event_notice(mrioc, false);
}
kfree(mr_sas_port);
}
/** * struct host_port - host port details * @sas_address: SAS Address of the attached device * @phy_mask: phy mask of host port * @handle: Device Handle of attached device * @iounit_port_id: port ID * @used: host port is already matched with sas port from sas_port_list * @lowest_phy: lowest phy ID of host port
*/ struct host_port {
u64 sas_address;
u64 phy_mask;
u16 handle;
u8 iounit_port_id;
u8 used;
u8 lowest_phy;
};
/** * mpi3mr_update_mr_sas_port - update sas port objects during reset * @mrioc: Adapter instance reference * @h_port: host_port object * @mr_sas_port: sas_port objects which needs to be updated * * Update the port ID of sas port object. Also add the phys if new phys got * added to current sas port and remove the phys if some phys are moved * out of the current sas port. * * Return: Nothing.
*/ staticvoid
mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, struct mpi3mr_sas_port *mr_sas_port)
{ struct mpi3mr_sas_phy *mr_sas_phy;
u64 phy_mask_xor;
u64 phys_to_be_added, phys_to_be_removed; int i;
/* Get the newly added phys bit map & removed phys bit map */
phy_mask_xor = mr_sas_port->phy_mask ^ h_port->phy_mask;
phys_to_be_added = h_port->phy_mask & phy_mask_xor;
phys_to_be_removed = mr_sas_port->phy_mask & phy_mask_xor;
/* * Register these new phys to current mr_sas_port's port. * if these phys are previously registered with another port * then delete these phys from that port first.
*/
for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u64)) {
mr_sas_phy = &mrioc->sas_hba.phy[i]; if (mr_sas_phy->phy_belongs_to_port)
mpi3mr_del_phy_from_an_existing_port(mrioc,
&mrioc->sas_hba, mr_sas_phy);
mpi3mr_add_phy_to_an_existing_port(mrioc,
&mrioc->sas_hba, mr_sas_phy,
mr_sas_port->remote_identify.sas_address,
mr_sas_port->hba_port);
}
/* Delete the phys which are not part of current mr_sas_port's port. */
for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u64)) {
mr_sas_phy = &mrioc->sas_hba.phy[i]; if (mr_sas_phy->phy_belongs_to_port)
mpi3mr_del_phy_from_an_existing_port(mrioc,
&mrioc->sas_hba, mr_sas_phy);
}
}
/** * mpi3mr_refresh_sas_ports - update host's sas ports during reset * @mrioc: Adapter instance reference * * Update the host's sas ports during reset by checking whether * sas ports are still intact or not. Add/remove phys if any hba * phys are (moved in)/(moved out) of sas port. Also update * io_unit_port if it got changed during reset. * * Return: Nothing.
*/ void
mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc)
{ struct host_port *h_port = NULL; int i, j, found, host_port_count = 0, port_idx;
u16 sz, attached_handle, ioc_status; struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL; struct mpi3_device_page0 dev_pg0; struct mpi3_device0_sas_sata_format *sasinf; struct mpi3mr_sas_port *mr_sas_port;
if (mrioc->logging_level & MPI3_DEBUG_RESET) {
ioc_info(mrioc, "Host port details before reset\n");
list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
port_list) {
ioc_info(mrioc, "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
mr_sas_port->hba_port->port_id,
mr_sas_port->remote_identify.sas_address,
mr_sas_port->phy_mask, mr_sas_port->lowest_phy);
}
mr_sas_port = NULL;
ioc_info(mrioc, "Host port details after reset\n"); for (i = 0; i < host_port_count; i++) {
ioc_info(mrioc, "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n",
h_port[i].iounit_port_id, h_port[i].sas_address,
h_port[i].phy_mask, h_port[i].lowest_phy);
}
}
/* mark all host sas port entries as dirty */
list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
port_list) {
mr_sas_port->marked_responding = 0;
mr_sas_port->hba_port->flags |= MPI3MR_HBA_PORT_FLAG_DIRTY;
}
/* First check for matching lowest phy */ for (i = 0; i < host_port_count; i++) {
mr_sas_port = NULL;
list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
port_list) { if (mr_sas_port->marked_responding) continue; if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address) continue; if (h_port[i].lowest_phy == mr_sas_port->lowest_phy) {
mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port); break;
}
}
}
/* In case if lowest phy is got enabled or disabled during reset */ for (i = 0; i < host_port_count; i++) { if (h_port[i].used) continue;
mr_sas_port = NULL;
list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
port_list) { if (mr_sas_port->marked_responding) continue; if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address) continue; if (h_port[i].phy_mask & mr_sas_port->phy_mask) {
mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port); break;
}
}
}
/* In case if expander cable is removed & connected to another HBA port during reset */ for (i = 0; i < host_port_count; i++) { if (h_port[i].used) continue;
mr_sas_port = NULL;
list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list,
port_list) { if (mr_sas_port->marked_responding) continue; if (h_port[i].sas_address != mr_sas_port->remote_identify.sas_address) continue;
mpi3mr_update_mr_sas_port(mrioc, &h_port[i], mr_sas_port); break;
}
}
out:
kfree(h_port);
kfree(sas_io_unit_pg0);
}
/** * mpi3mr_refresh_expanders - Refresh expander device exposure * @mrioc: Adapter instance reference * * This is executed post controller reset to identify any * missing expander devices during reset and remove from the upper layers * or expose any newly detected expander device to the upper layers. * * Return: Nothing.
*/ void
mpi3mr_refresh_expanders(struct mpi3mr_ioc *mrioc)
{ struct mpi3mr_sas_node *sas_expander, *sas_expander_next; struct mpi3_sas_expander_page0 expander_pg0;
u16 ioc_status, handle;
u64 sas_address; int i; unsignedlong flags; struct mpi3mr_hba_port *hba_port;
/* Search for responding expander devices and add them if they are newly got added */ while (true) { if ((mpi3mr_cfg_get_sas_exp_pg0(mrioc, &ioc_status, &expander_pg0, sizeof(struct mpi3_sas_expander_page0),
MPI3_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
dprint_reset(mrioc, "failed to read exp pg0 for handle(0x%04x) at %s:%d/%s()!\n",
handle, __FILE__, __LINE__, __func__); break;
}
if (ioc_status != MPI3_IOCSTATUS_SUCCESS) {
dprint_reset(mrioc, "ioc_status(0x%x) while reading exp pg0 for handle:(0x%04x), %s:%d/%s()!\n",
ioc_status, handle, __FILE__, __LINE__, __func__); break;
}
if (!sas_expander) {
mpi3mr_sas_host_refresh(mrioc);
mpi3mr_expander_add(mrioc, handle); continue;
}
sas_expander->non_responding = 0; if (sas_expander->handle == handle) continue;
sas_expander->handle = handle; for (i = 0 ; i < sas_expander->num_phys ; i++)
sas_expander->phy[i].handle = handle;
}
/* * Delete non responding expander devices and the corresponding * hba_port if the non responding expander device's parent device * is a host node.
*/
sas_expander = NULL;
spin_lock_irqsave(&mrioc->sas_node_lock, flags);
list_for_each_entry_safe_reverse(sas_expander, sas_expander_next,
&mrioc->sas_expander_list, list) { if (sas_expander->non_responding) {
spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
mpi3mr_expander_node_remove(mrioc, sas_expander);
spin_lock_irqsave(&mrioc->sas_node_lock, flags);
}
}
spin_unlock_irqrestore(&mrioc->sas_node_lock, flags);
}
/** * mpi3mr_expander_node_add - insert an expander to the list. * @mrioc: Adapter instance reference * @sas_expander: Expander sas node * Context: This function will acquire sas_node_lock. * * Adding new object to the ioc->sas_expander_list. * * Return: None.
*/ staticvoid mpi3mr_expander_node_add(struct mpi3mr_ioc *mrioc, struct mpi3mr_sas_node *sas_expander)
{ unsignedlong flags;
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.