Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Serial Attached SCSI (SAS) Phy 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 #include <scsi/scsi_host.h>
0011 #include <scsi/scsi_transport.h>
0012 #include <scsi/scsi_transport_sas.h>
0013 #include "scsi_sas_internal.h"
0014 
0015 /* ---------- Phy events ---------- */
0016 
0017 static void sas_phye_loss_of_signal(struct work_struct *work)
0018 {
0019     struct asd_sas_event *ev = to_asd_sas_event(work);
0020     struct asd_sas_phy *phy = ev->phy;
0021 
0022     phy->error = 0;
0023     sas_deform_port(phy, 1);
0024 }
0025 
0026 static void sas_phye_oob_done(struct work_struct *work)
0027 {
0028     struct asd_sas_event *ev = to_asd_sas_event(work);
0029     struct asd_sas_phy *phy = ev->phy;
0030 
0031     phy->error = 0;
0032 }
0033 
0034 static void sas_phye_oob_error(struct work_struct *work)
0035 {
0036     struct asd_sas_event *ev = to_asd_sas_event(work);
0037     struct asd_sas_phy *phy = ev->phy;
0038     struct sas_ha_struct *sas_ha = phy->ha;
0039     struct asd_sas_port *port = phy->port;
0040     struct sas_internal *i =
0041         to_sas_internal(sas_ha->core.shost->transportt);
0042 
0043     sas_deform_port(phy, 1);
0044 
0045     if (!port && phy->enabled && i->dft->lldd_control_phy) {
0046         phy->error++;
0047         switch (phy->error) {
0048         case 1:
0049         case 2:
0050             i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET,
0051                          NULL);
0052             break;
0053         case 3:
0054         default:
0055             phy->error = 0;
0056             phy->enabled = 0;
0057             i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
0058             break;
0059         }
0060     }
0061 }
0062 
0063 static void sas_phye_spinup_hold(struct work_struct *work)
0064 {
0065     struct asd_sas_event *ev = to_asd_sas_event(work);
0066     struct asd_sas_phy *phy = ev->phy;
0067     struct sas_ha_struct *sas_ha = phy->ha;
0068     struct sas_internal *i =
0069         to_sas_internal(sas_ha->core.shost->transportt);
0070 
0071     phy->error = 0;
0072     i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
0073 }
0074 
0075 static void sas_phye_resume_timeout(struct work_struct *work)
0076 {
0077     struct asd_sas_event *ev = to_asd_sas_event(work);
0078     struct asd_sas_phy *phy = ev->phy;
0079 
0080     /* phew, lldd got the phy back in the nick of time */
0081     if (!phy->suspended) {
0082         dev_info(&phy->phy->dev, "resume timeout cancelled\n");
0083         return;
0084     }
0085 
0086     phy->error = 0;
0087     phy->suspended = 0;
0088     sas_deform_port(phy, 1);
0089 }
0090 
0091 
0092 static void sas_phye_shutdown(struct work_struct *work)
0093 {
0094     struct asd_sas_event *ev = to_asd_sas_event(work);
0095     struct asd_sas_phy *phy = ev->phy;
0096     struct sas_ha_struct *sas_ha = phy->ha;
0097     struct sas_internal *i =
0098         to_sas_internal(sas_ha->core.shost->transportt);
0099 
0100     if (phy->enabled) {
0101         int ret;
0102 
0103         phy->error = 0;
0104         phy->enabled = 0;
0105         ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
0106         if (ret)
0107             pr_notice("lldd disable phy%d returned %d\n", phy->id,
0108                   ret);
0109     } else
0110         pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id);
0111     phy->in_shutdown = 0;
0112 }
0113 
0114 /* ---------- Phy class registration ---------- */
0115 
0116 int sas_register_phys(struct sas_ha_struct *sas_ha)
0117 {
0118     int i;
0119 
0120     /* Now register the phys. */
0121     for (i = 0; i < sas_ha->num_phys; i++) {
0122         struct asd_sas_phy *phy = sas_ha->sas_phy[i];
0123 
0124         phy->error = 0;
0125         atomic_set(&phy->event_nr, 0);
0126         INIT_LIST_HEAD(&phy->port_phy_el);
0127 
0128         phy->port = NULL;
0129         phy->ha = sas_ha;
0130         spin_lock_init(&phy->frame_rcvd_lock);
0131         spin_lock_init(&phy->sas_prim_lock);
0132         phy->frame_rcvd_size = 0;
0133 
0134         phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, i);
0135         if (!phy->phy)
0136             return -ENOMEM;
0137 
0138         phy->phy->identify.initiator_port_protocols =
0139             phy->iproto;
0140         phy->phy->identify.target_port_protocols = phy->tproto;
0141         phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr);
0142         phy->phy->identify.phy_identifier = i;
0143         phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
0144         phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
0145         phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
0146         phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
0147         phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
0148 
0149         sas_phy_add(phy->phy);
0150     }
0151 
0152     return 0;
0153 }
0154 
0155 const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
0156     [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
0157     [PHYE_OOB_DONE] = sas_phye_oob_done,
0158     [PHYE_OOB_ERROR] = sas_phye_oob_error,
0159     [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
0160     [PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
0161     [PHYE_SHUTDOWN] = sas_phye_shutdown,
0162 };