Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Serial Attached SCSI (SAS) Port class
0004  *
0005  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
0006  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
0007  */
0008 
0009 #include "sas_internal.h"
0010 
0011 #include <scsi/scsi_transport.h>
0012 #include <scsi/scsi_transport_sas.h>
0013 #include "scsi_sas_internal.h"
0014 
0015 static bool phy_is_wideport_member(struct asd_sas_port *port, struct asd_sas_phy *phy)
0016 {
0017     struct sas_ha_struct *sas_ha = phy->ha;
0018 
0019     if (memcmp(port->attached_sas_addr, phy->attached_sas_addr,
0020            SAS_ADDR_SIZE) != 0 || (sas_ha->strict_wide_ports &&
0021          memcmp(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE) != 0))
0022         return false;
0023     return true;
0024 }
0025 
0026 static void sas_resume_port(struct asd_sas_phy *phy)
0027 {
0028     struct domain_device *dev, *n;
0029     struct asd_sas_port *port = phy->port;
0030     struct sas_ha_struct *sas_ha = phy->ha;
0031     struct sas_internal *si = to_sas_internal(sas_ha->core.shost->transportt);
0032 
0033     if (si->dft->lldd_port_formed)
0034         si->dft->lldd_port_formed(phy);
0035 
0036     if (port->suspended)
0037         port->suspended = 0;
0038     else {
0039         /* we only need to handle "link returned" actions once */
0040         return;
0041     }
0042 
0043     /* if the port came back:
0044      * 1/ presume every device came back
0045      * 2/ force the next revalidation to check all expander phys
0046      */
0047     list_for_each_entry_safe(dev, n, &port->dev_list, dev_list_node) {
0048         int i, rc;
0049 
0050         rc = sas_notify_lldd_dev_found(dev);
0051         if (rc) {
0052             sas_unregister_dev(port, dev);
0053             sas_destruct_devices(port);
0054             continue;
0055         }
0056 
0057         if (dev_is_expander(dev->dev_type)) {
0058             dev->ex_dev.ex_change_count = -1;
0059             for (i = 0; i < dev->ex_dev.num_phys; i++) {
0060                 struct ex_phy *phy = &dev->ex_dev.ex_phy[i];
0061 
0062                 phy->phy_change_count = -1;
0063             }
0064         }
0065     }
0066 
0067     sas_discover_event(port, DISCE_RESUME);
0068 }
0069 
0070 static void sas_form_port_add_phy(struct asd_sas_port *port,
0071                   struct asd_sas_phy *phy, bool wideport)
0072 {
0073     list_add_tail(&phy->port_phy_el, &port->phy_list);
0074     sas_phy_set_target(phy, port->port_dev);
0075     phy->port = port;
0076     port->num_phys++;
0077     port->phy_mask |= (1U << phy->id);
0078 
0079     if (wideport)
0080         pr_debug("phy%d matched wide port%d\n", phy->id,
0081              port->id);
0082     else
0083         memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE);
0084 
0085     if (*(u64 *)port->attached_sas_addr == 0) {
0086         port->class = phy->class;
0087         memcpy(port->attached_sas_addr, phy->attached_sas_addr,
0088                SAS_ADDR_SIZE);
0089         port->iproto = phy->iproto;
0090         port->tproto = phy->tproto;
0091         port->oob_mode = phy->oob_mode;
0092         port->linkrate = phy->linkrate;
0093     } else {
0094         port->linkrate = max(port->linkrate, phy->linkrate);
0095     }
0096 }
0097 
0098 /**
0099  * sas_form_port - add this phy to a port
0100  * @phy: the phy of interest
0101  *
0102  * This function adds this phy to an existing port, thus creating a wide
0103  * port, or it creates a port and adds the phy to the port.
0104  */
0105 static void sas_form_port(struct asd_sas_phy *phy)
0106 {
0107     int i;
0108     struct sas_ha_struct *sas_ha = phy->ha;
0109     struct asd_sas_port *port = phy->port;
0110     struct domain_device *port_dev = NULL;
0111     struct sas_internal *si =
0112         to_sas_internal(sas_ha->core.shost->transportt);
0113     unsigned long flags;
0114 
0115     if (port) {
0116         if (!phy_is_wideport_member(port, phy))
0117             sas_deform_port(phy, 0);
0118         else if (phy->suspended) {
0119             phy->suspended = 0;
0120             sas_resume_port(phy);
0121 
0122             /* phy came back, try to cancel the timeout */
0123             wake_up(&sas_ha->eh_wait_q);
0124             return;
0125         } else {
0126             pr_info("%s: phy%d belongs to port%d already(%d)!\n",
0127                 __func__, phy->id, phy->port->id,
0128                 phy->port->num_phys);
0129             return;
0130         }
0131     }
0132 
0133     /* see if the phy should be part of a wide port */
0134     spin_lock_irqsave(&sas_ha->phy_port_lock, flags);
0135     for (i = 0; i < sas_ha->num_phys; i++) {
0136         port = sas_ha->sas_port[i];
0137         spin_lock(&port->phy_list_lock);
0138         if (*(u64 *) port->sas_addr &&
0139             phy_is_wideport_member(port, phy) && port->num_phys > 0) {
0140             /* wide port */
0141             port_dev = port->port_dev;
0142             sas_form_port_add_phy(port, phy, true);
0143             spin_unlock(&port->phy_list_lock);
0144             break;
0145         }
0146         spin_unlock(&port->phy_list_lock);
0147     }
0148     /* The phy does not match any existing port, create a new one */
0149     if (i == sas_ha->num_phys) {
0150         for (i = 0; i < sas_ha->num_phys; i++) {
0151             port = sas_ha->sas_port[i];
0152             spin_lock(&port->phy_list_lock);
0153             if (*(u64 *)port->sas_addr == 0
0154                 && port->num_phys == 0) {
0155                 port_dev = port->port_dev;
0156                 sas_form_port_add_phy(port, phy, false);
0157                 spin_unlock(&port->phy_list_lock);
0158                 break;
0159             }
0160             spin_unlock(&port->phy_list_lock);
0161         }
0162 
0163         if (i >= sas_ha->num_phys) {
0164             pr_err("%s: couldn't find a free port, bug?\n",
0165                    __func__);
0166             spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
0167             return;
0168         }
0169     }
0170     spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
0171 
0172     if (!port->port) {
0173         port->port = sas_port_alloc(phy->phy->dev.parent, port->id);
0174         BUG_ON(!port->port);
0175         sas_port_add(port->port);
0176     }
0177     sas_port_add_phy(port->port, phy->phy);
0178 
0179     pr_debug("%s added to %s, phy_mask:0x%x (%016llx)\n",
0180          dev_name(&phy->phy->dev), dev_name(&port->port->dev),
0181          port->phy_mask,
0182          SAS_ADDR(port->attached_sas_addr));
0183 
0184     if (port_dev)
0185         port_dev->pathways = port->num_phys;
0186 
0187     /* Tell the LLDD about this port formation. */
0188     if (si->dft->lldd_port_formed)
0189         si->dft->lldd_port_formed(phy);
0190 
0191     sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN);
0192     /* Only insert a revalidate event after initial discovery */
0193     if (port_dev && dev_is_expander(port_dev->dev_type)) {
0194         struct expander_device *ex_dev = &port_dev->ex_dev;
0195 
0196         ex_dev->ex_change_count = -1;
0197         sas_discover_event(port, DISCE_REVALIDATE_DOMAIN);
0198     }
0199     flush_workqueue(sas_ha->disco_q);
0200 }
0201 
0202 /**
0203  * sas_deform_port - remove this phy from the port it belongs to
0204  * @phy: the phy of interest
0205  * @gone: whether or not the PHY is gone
0206  *
0207  * This is called when the physical link to the other phy has been
0208  * lost (on this phy), in Event thread context. We cannot delay here.
0209  */
0210 void sas_deform_port(struct asd_sas_phy *phy, int gone)
0211 {
0212     struct sas_ha_struct *sas_ha = phy->ha;
0213     struct asd_sas_port *port = phy->port;
0214     struct sas_internal *si =
0215         to_sas_internal(sas_ha->core.shost->transportt);
0216     struct domain_device *dev;
0217     unsigned long flags;
0218 
0219     if (!port)
0220         return;       /* done by a phy event */
0221 
0222     dev = port->port_dev;
0223     if (dev)
0224         dev->pathways--;
0225 
0226     if (port->num_phys == 1) {
0227         sas_unregister_domain_devices(port, gone);
0228         sas_destruct_devices(port);
0229         sas_port_delete(port->port);
0230         port->port = NULL;
0231     } else {
0232         sas_port_delete_phy(port->port, phy->phy);
0233         sas_device_set_phy(dev, port->port);
0234     }
0235 
0236     if (si->dft->lldd_port_deformed)
0237         si->dft->lldd_port_deformed(phy);
0238 
0239     spin_lock_irqsave(&sas_ha->phy_port_lock, flags);
0240     spin_lock(&port->phy_list_lock);
0241 
0242     list_del_init(&phy->port_phy_el);
0243     sas_phy_set_target(phy, NULL);
0244     phy->port = NULL;
0245     port->num_phys--;
0246     port->phy_mask &= ~(1U << phy->id);
0247 
0248     if (port->num_phys == 0) {
0249         INIT_LIST_HEAD(&port->phy_list);
0250         memset(port->sas_addr, 0, SAS_ADDR_SIZE);
0251         memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE);
0252         port->class = 0;
0253         port->iproto = 0;
0254         port->tproto = 0;
0255         port->oob_mode = 0;
0256         port->phy_mask = 0;
0257     }
0258     spin_unlock(&port->phy_list_lock);
0259     spin_unlock_irqrestore(&sas_ha->phy_port_lock, flags);
0260 
0261     /* Only insert revalidate event if the port still has members */
0262     if (port->port && dev && dev_is_expander(dev->dev_type)) {
0263         struct expander_device *ex_dev = &dev->ex_dev;
0264 
0265         ex_dev->ex_change_count = -1;
0266         sas_discover_event(port, DISCE_REVALIDATE_DOMAIN);
0267     }
0268     flush_workqueue(sas_ha->disco_q);
0269 
0270     return;
0271 }
0272 
0273 /* ---------- SAS port events ---------- */
0274 
0275 void sas_porte_bytes_dmaed(struct work_struct *work)
0276 {
0277     struct asd_sas_event *ev = to_asd_sas_event(work);
0278     struct asd_sas_phy *phy = ev->phy;
0279 
0280     sas_form_port(phy);
0281 }
0282 
0283 void sas_porte_broadcast_rcvd(struct work_struct *work)
0284 {
0285     struct asd_sas_event *ev = to_asd_sas_event(work);
0286     struct asd_sas_phy *phy = ev->phy;
0287     unsigned long flags;
0288     u32 prim;
0289 
0290     spin_lock_irqsave(&phy->sas_prim_lock, flags);
0291     prim = phy->sas_prim;
0292     spin_unlock_irqrestore(&phy->sas_prim_lock, flags);
0293 
0294     pr_debug("broadcast received: %d\n", prim);
0295     sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN);
0296 
0297     if (phy->port)
0298         flush_workqueue(phy->port->ha->disco_q);
0299 }
0300 
0301 void sas_porte_link_reset_err(struct work_struct *work)
0302 {
0303     struct asd_sas_event *ev = to_asd_sas_event(work);
0304     struct asd_sas_phy *phy = ev->phy;
0305 
0306     sas_deform_port(phy, 1);
0307 }
0308 
0309 void sas_porte_timer_event(struct work_struct *work)
0310 {
0311     struct asd_sas_event *ev = to_asd_sas_event(work);
0312     struct asd_sas_phy *phy = ev->phy;
0313 
0314     sas_deform_port(phy, 1);
0315 }
0316 
0317 void sas_porte_hard_reset(struct work_struct *work)
0318 {
0319     struct asd_sas_event *ev = to_asd_sas_event(work);
0320     struct asd_sas_phy *phy = ev->phy;
0321 
0322     sas_deform_port(phy, 1);
0323 }
0324 
0325 /* ---------- SAS port registration ---------- */
0326 
0327 static void sas_init_port(struct asd_sas_port *port,
0328               struct sas_ha_struct *sas_ha, int i)
0329 {
0330     memset(port, 0, sizeof(*port));
0331     port->id = i;
0332     INIT_LIST_HEAD(&port->dev_list);
0333     INIT_LIST_HEAD(&port->disco_list);
0334     INIT_LIST_HEAD(&port->destroy_list);
0335     INIT_LIST_HEAD(&port->sas_port_del_list);
0336     spin_lock_init(&port->phy_list_lock);
0337     INIT_LIST_HEAD(&port->phy_list);
0338     port->ha = sas_ha;
0339 
0340     spin_lock_init(&port->dev_list_lock);
0341 }
0342 
0343 int sas_register_ports(struct sas_ha_struct *sas_ha)
0344 {
0345     int i;
0346 
0347     /* initialize the ports and discovery */
0348     for (i = 0; i < sas_ha->num_phys; i++) {
0349         struct asd_sas_port *port = sas_ha->sas_port[i];
0350 
0351         sas_init_port(port, sas_ha, i);
0352         sas_init_disc(&port->disc, port);
0353     }
0354     return 0;
0355 }
0356 
0357 void sas_unregister_ports(struct sas_ha_struct *sas_ha)
0358 {
0359     int i;
0360 
0361     for (i = 0; i < sas_ha->num_phys; i++)
0362         if (sas_ha->sas_phy[i]->port)
0363             sas_deform_port(sas_ha->sas_phy[i], 0);
0364 
0365 }
0366 
0367 const work_func_t sas_port_event_fns[PORT_NUM_EVENTS] = {
0368     [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed,
0369     [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd,
0370     [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err,
0371     [PORTE_TIMER_EVENT] = sas_porte_timer_event,
0372     [PORTE_HARD_RESET] = sas_porte_hard_reset,
0373 };