Linux Audio

Check our new training course

Loading...
v6.8
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Serial Attached SCSI (SAS) Phy class
  4 *
  5 * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
  6 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
  7 */
  8
  9#include "sas_internal.h"
 10#include <scsi/scsi_host.h>
 11#include <scsi/scsi_transport.h>
 12#include <scsi/scsi_transport_sas.h>
 13#include "scsi_sas_internal.h"
 14
 15/* ---------- Phy events ---------- */
 16
 17static void sas_phye_loss_of_signal(struct work_struct *work)
 18{
 19	struct asd_sas_event *ev = to_asd_sas_event(work);
 20	struct asd_sas_phy *phy = ev->phy;
 21
 22	phy->error = 0;
 23	sas_deform_port(phy, 1);
 24}
 25
 26static void sas_phye_oob_done(struct work_struct *work)
 27{
 28	struct asd_sas_event *ev = to_asd_sas_event(work);
 29	struct asd_sas_phy *phy = ev->phy;
 30
 31	phy->error = 0;
 32}
 33
 34static void sas_phye_oob_error(struct work_struct *work)
 35{
 36	struct asd_sas_event *ev = to_asd_sas_event(work);
 37	struct asd_sas_phy *phy = ev->phy;
 38	struct sas_ha_struct *sas_ha = phy->ha;
 39	struct asd_sas_port *port = phy->port;
 40	struct sas_internal *i =
 41		to_sas_internal(sas_ha->shost->transportt);
 42
 43	sas_deform_port(phy, 1);
 44
 45	if (!port && phy->enabled && i->dft->lldd_control_phy) {
 46		phy->error++;
 47		switch (phy->error) {
 48		case 1:
 49		case 2:
 50			i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET,
 51						 NULL);
 52			break;
 53		case 3:
 54		default:
 55			phy->error = 0;
 56			phy->enabled = 0;
 57			i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
 58			break;
 59		}
 60	}
 61}
 62
 63static void sas_phye_spinup_hold(struct work_struct *work)
 64{
 65	struct asd_sas_event *ev = to_asd_sas_event(work);
 66	struct asd_sas_phy *phy = ev->phy;
 67	struct sas_ha_struct *sas_ha = phy->ha;
 68	struct sas_internal *i =
 69		to_sas_internal(sas_ha->shost->transportt);
 70
 71	phy->error = 0;
 72	i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
 73}
 74
 75static void sas_phye_resume_timeout(struct work_struct *work)
 76{
 77	struct asd_sas_event *ev = to_asd_sas_event(work);
 78	struct asd_sas_phy *phy = ev->phy;
 79
 80	/* phew, lldd got the phy back in the nick of time */
 81	if (!phy->suspended) {
 82		dev_info(&phy->phy->dev, "resume timeout cancelled\n");
 83		return;
 84	}
 85
 86	phy->error = 0;
 87	phy->suspended = 0;
 88	sas_deform_port(phy, 1);
 89}
 90
 91
 92static void sas_phye_shutdown(struct work_struct *work)
 93{
 94	struct asd_sas_event *ev = to_asd_sas_event(work);
 95	struct asd_sas_phy *phy = ev->phy;
 96	struct sas_ha_struct *sas_ha = phy->ha;
 97	struct sas_internal *i =
 98		to_sas_internal(sas_ha->shost->transportt);
 99
100	if (phy->enabled) {
101		int ret;
102
103		phy->error = 0;
104		phy->enabled = 0;
105		ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
106		if (ret)
107			pr_notice("lldd disable phy%d returned %d\n", phy->id,
108				  ret);
109	} else
110		pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id);
111	phy->in_shutdown = 0;
112}
113
114/* ---------- Phy class registration ---------- */
115
116int sas_register_phys(struct sas_ha_struct *sas_ha)
117{
118	int i;
119
120	/* Now register the phys. */
121	for (i = 0; i < sas_ha->num_phys; i++) {
122		struct asd_sas_phy *phy = sas_ha->sas_phy[i];
123
124		phy->error = 0;
125		atomic_set(&phy->event_nr, 0);
126		INIT_LIST_HEAD(&phy->port_phy_el);
127
128		phy->port = NULL;
129		phy->ha = sas_ha;
130		spin_lock_init(&phy->frame_rcvd_lock);
131		spin_lock_init(&phy->sas_prim_lock);
132		phy->frame_rcvd_size = 0;
133
134		phy->phy = sas_phy_alloc(&sas_ha->shost->shost_gendev, i);
135		if (!phy->phy)
136			return -ENOMEM;
137
138		phy->phy->identify.initiator_port_protocols =
139			phy->iproto;
140		phy->phy->identify.target_port_protocols = phy->tproto;
141		phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr);
142		phy->phy->identify.phy_identifier = i;
143		phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
144		phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
145		phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
146		phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
147		phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
148
149		sas_phy_add(phy->phy);
150	}
151
152	return 0;
153}
154
155const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
156	[PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
157	[PHYE_OOB_DONE] = sas_phye_oob_done,
158	[PHYE_OOB_ERROR] = sas_phye_oob_error,
159	[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
160	[PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
161	[PHYE_SHUTDOWN] = sas_phye_shutdown,
162};
v5.4
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Serial Attached SCSI (SAS) Phy class
  4 *
  5 * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
  6 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
  7 */
  8
  9#include "sas_internal.h"
 10#include <scsi/scsi_host.h>
 11#include <scsi/scsi_transport.h>
 12#include <scsi/scsi_transport_sas.h>
 13#include "../scsi_sas_internal.h"
 14
 15/* ---------- Phy events ---------- */
 16
 17static void sas_phye_loss_of_signal(struct work_struct *work)
 18{
 19	struct asd_sas_event *ev = to_asd_sas_event(work);
 20	struct asd_sas_phy *phy = ev->phy;
 21
 22	phy->error = 0;
 23	sas_deform_port(phy, 1);
 24}
 25
 26static void sas_phye_oob_done(struct work_struct *work)
 27{
 28	struct asd_sas_event *ev = to_asd_sas_event(work);
 29	struct asd_sas_phy *phy = ev->phy;
 30
 31	phy->error = 0;
 32}
 33
 34static void sas_phye_oob_error(struct work_struct *work)
 35{
 36	struct asd_sas_event *ev = to_asd_sas_event(work);
 37	struct asd_sas_phy *phy = ev->phy;
 38	struct sas_ha_struct *sas_ha = phy->ha;
 39	struct asd_sas_port *port = phy->port;
 40	struct sas_internal *i =
 41		to_sas_internal(sas_ha->core.shost->transportt);
 42
 43	sas_deform_port(phy, 1);
 44
 45	if (!port && phy->enabled && i->dft->lldd_control_phy) {
 46		phy->error++;
 47		switch (phy->error) {
 48		case 1:
 49		case 2:
 50			i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET,
 51						 NULL);
 52			break;
 53		case 3:
 54		default:
 55			phy->error = 0;
 56			phy->enabled = 0;
 57			i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
 58			break;
 59		}
 60	}
 61}
 62
 63static void sas_phye_spinup_hold(struct work_struct *work)
 64{
 65	struct asd_sas_event *ev = to_asd_sas_event(work);
 66	struct asd_sas_phy *phy = ev->phy;
 67	struct sas_ha_struct *sas_ha = phy->ha;
 68	struct sas_internal *i =
 69		to_sas_internal(sas_ha->core.shost->transportt);
 70
 71	phy->error = 0;
 72	i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
 73}
 74
 75static void sas_phye_resume_timeout(struct work_struct *work)
 76{
 77	struct asd_sas_event *ev = to_asd_sas_event(work);
 78	struct asd_sas_phy *phy = ev->phy;
 79
 80	/* phew, lldd got the phy back in the nick of time */
 81	if (!phy->suspended) {
 82		dev_info(&phy->phy->dev, "resume timeout cancelled\n");
 83		return;
 84	}
 85
 86	phy->error = 0;
 87	phy->suspended = 0;
 88	sas_deform_port(phy, 1);
 89}
 90
 91
 92static void sas_phye_shutdown(struct work_struct *work)
 93{
 94	struct asd_sas_event *ev = to_asd_sas_event(work);
 95	struct asd_sas_phy *phy = ev->phy;
 96	struct sas_ha_struct *sas_ha = phy->ha;
 97	struct sas_internal *i =
 98		to_sas_internal(sas_ha->core.shost->transportt);
 99
100	if (phy->enabled) {
101		int ret;
102
103		phy->error = 0;
104		phy->enabled = 0;
105		ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
106		if (ret)
107			pr_notice("lldd disable phy%d returned %d\n", phy->id,
108				  ret);
109	} else
110		pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id);
111	phy->in_shutdown = 0;
112}
113
114/* ---------- Phy class registration ---------- */
115
116int sas_register_phys(struct sas_ha_struct *sas_ha)
117{
118	int i;
119
120	/* Now register the phys. */
121	for (i = 0; i < sas_ha->num_phys; i++) {
122		struct asd_sas_phy *phy = sas_ha->sas_phy[i];
123
124		phy->error = 0;
125		atomic_set(&phy->event_nr, 0);
126		INIT_LIST_HEAD(&phy->port_phy_el);
127
128		phy->port = NULL;
129		phy->ha = sas_ha;
130		spin_lock_init(&phy->frame_rcvd_lock);
131		spin_lock_init(&phy->sas_prim_lock);
132		phy->frame_rcvd_size = 0;
133
134		phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, i);
135		if (!phy->phy)
136			return -ENOMEM;
137
138		phy->phy->identify.initiator_port_protocols =
139			phy->iproto;
140		phy->phy->identify.target_port_protocols = phy->tproto;
141		phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr);
142		phy->phy->identify.phy_identifier = i;
143		phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
144		phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
145		phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
146		phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
147		phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
148
149		sas_phy_add(phy->phy);
150	}
151
152	return 0;
153}
154
155const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
156	[PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
157	[PHYE_OOB_DONE] = sas_phye_oob_done,
158	[PHYE_OOB_ERROR] = sas_phye_oob_error,
159	[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
160	[PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
161	[PHYE_SHUTDOWN] = sas_phye_shutdown,
162};