xref: /openbmc/linux/drivers/scsi/libsas/sas_phy.c (revision 1136a022)
186b89cb0SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
22908d778SJames Bottomley /*
32908d778SJames Bottomley  * Serial Attached SCSI (SAS) Phy class
42908d778SJames Bottomley  *
52908d778SJames Bottomley  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
62908d778SJames Bottomley  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
72908d778SJames Bottomley  */
82908d778SJames Bottomley 
92908d778SJames Bottomley #include "sas_internal.h"
102908d778SJames Bottomley #include <scsi/scsi_host.h>
112908d778SJames Bottomley #include <scsi/scsi_transport.h>
122908d778SJames Bottomley #include <scsi/scsi_transport_sas.h>
13e15f669cSJason Yan #include "scsi_sas_internal.h"
142908d778SJames Bottomley 
152908d778SJames Bottomley /* ---------- Phy events ---------- */
162908d778SJames Bottomley 
sas_phye_loss_of_signal(struct work_struct * work)17c4028958SDavid Howells static void sas_phye_loss_of_signal(struct work_struct *work)
182908d778SJames Bottomley {
1922b9153fSDan Williams 	struct asd_sas_event *ev = to_asd_sas_event(work);
20c4028958SDavid Howells 	struct asd_sas_phy *phy = ev->phy;
212908d778SJames Bottomley 
222908d778SJames Bottomley 	phy->error = 0;
2390f1e10dSDan Williams 	sas_deform_port(phy, 1);
242908d778SJames Bottomley }
252908d778SJames Bottomley 
sas_phye_oob_done(struct work_struct * work)26c4028958SDavid Howells static void sas_phye_oob_done(struct work_struct *work)
272908d778SJames Bottomley {
2822b9153fSDan Williams 	struct asd_sas_event *ev = to_asd_sas_event(work);
29c4028958SDavid Howells 	struct asd_sas_phy *phy = ev->phy;
302908d778SJames Bottomley 
312908d778SJames Bottomley 	phy->error = 0;
322908d778SJames Bottomley }
332908d778SJames Bottomley 
sas_phye_oob_error(struct work_struct * work)34c4028958SDavid Howells static void sas_phye_oob_error(struct work_struct *work)
352908d778SJames Bottomley {
3622b9153fSDan Williams 	struct asd_sas_event *ev = to_asd_sas_event(work);
37c4028958SDavid Howells 	struct asd_sas_phy *phy = ev->phy;
382908d778SJames Bottomley 	struct sas_ha_struct *sas_ha = phy->ha;
392908d778SJames Bottomley 	struct asd_sas_port *port = phy->port;
402908d778SJames Bottomley 	struct sas_internal *i =
41*1136a022SJohn Garry 		to_sas_internal(sas_ha->shost->transportt);
422908d778SJames Bottomley 
4390f1e10dSDan Williams 	sas_deform_port(phy, 1);
442908d778SJames Bottomley 
452908d778SJames Bottomley 	if (!port && phy->enabled && i->dft->lldd_control_phy) {
462908d778SJames Bottomley 		phy->error++;
472908d778SJames Bottomley 		switch (phy->error) {
482908d778SJames Bottomley 		case 1:
492908d778SJames Bottomley 		case 2:
50a01e70e5SJames Bottomley 			i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET,
51a01e70e5SJames Bottomley 						 NULL);
522908d778SJames Bottomley 			break;
532908d778SJames Bottomley 		case 3:
542908d778SJames Bottomley 		default:
552908d778SJames Bottomley 			phy->error = 0;
562908d778SJames Bottomley 			phy->enabled = 0;
57a01e70e5SJames Bottomley 			i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
582908d778SJames Bottomley 			break;
592908d778SJames Bottomley 		}
602908d778SJames Bottomley 	}
612908d778SJames Bottomley }
622908d778SJames Bottomley 
sas_phye_spinup_hold(struct work_struct * work)63c4028958SDavid Howells static void sas_phye_spinup_hold(struct work_struct *work)
642908d778SJames Bottomley {
6522b9153fSDan Williams 	struct asd_sas_event *ev = to_asd_sas_event(work);
66c4028958SDavid Howells 	struct asd_sas_phy *phy = ev->phy;
672908d778SJames Bottomley 	struct sas_ha_struct *sas_ha = phy->ha;
682908d778SJames Bottomley 	struct sas_internal *i =
69*1136a022SJohn Garry 		to_sas_internal(sas_ha->shost->transportt);
702908d778SJames Bottomley 
712908d778SJames Bottomley 	phy->error = 0;
72a01e70e5SJames Bottomley 	i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD, NULL);
732908d778SJames Bottomley }
742908d778SJames Bottomley 
sas_phye_resume_timeout(struct work_struct * work)75303694eeSDan Williams static void sas_phye_resume_timeout(struct work_struct *work)
76303694eeSDan Williams {
77303694eeSDan Williams 	struct asd_sas_event *ev = to_asd_sas_event(work);
78303694eeSDan Williams 	struct asd_sas_phy *phy = ev->phy;
79303694eeSDan Williams 
80303694eeSDan Williams 	/* phew, lldd got the phy back in the nick of time */
81303694eeSDan Williams 	if (!phy->suspended) {
82303694eeSDan Williams 		dev_info(&phy->phy->dev, "resume timeout cancelled\n");
83303694eeSDan Williams 		return;
84303694eeSDan Williams 	}
85303694eeSDan Williams 
86303694eeSDan Williams 	phy->error = 0;
87303694eeSDan Williams 	phy->suspended = 0;
88303694eeSDan Williams 	sas_deform_port(phy, 1);
89303694eeSDan Williams }
90303694eeSDan Williams 
91303694eeSDan Williams 
sas_phye_shutdown(struct work_struct * work)92f12486e0SJason Yan static void sas_phye_shutdown(struct work_struct *work)
93f12486e0SJason Yan {
94f12486e0SJason Yan 	struct asd_sas_event *ev = to_asd_sas_event(work);
95f12486e0SJason Yan 	struct asd_sas_phy *phy = ev->phy;
96f12486e0SJason Yan 	struct sas_ha_struct *sas_ha = phy->ha;
97f12486e0SJason Yan 	struct sas_internal *i =
98*1136a022SJohn Garry 		to_sas_internal(sas_ha->shost->transportt);
99f12486e0SJason Yan 
100f12486e0SJason Yan 	if (phy->enabled) {
101f12486e0SJason Yan 		int ret;
102f12486e0SJason Yan 
103f12486e0SJason Yan 		phy->error = 0;
104f12486e0SJason Yan 		phy->enabled = 0;
105f12486e0SJason Yan 		ret = i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE, NULL);
106f12486e0SJason Yan 		if (ret)
1073c236f8cSJohn Garry 			pr_notice("lldd disable phy%d returned %d\n", phy->id,
1083c236f8cSJohn Garry 				  ret);
109f12486e0SJason Yan 	} else
1103c236f8cSJohn Garry 		pr_notice("phy%d is not enabled, cannot shutdown\n", phy->id);
11104cf8b32SJason Yan 	phy->in_shutdown = 0;
112f12486e0SJason Yan }
113f12486e0SJason Yan 
1142908d778SJames Bottomley /* ---------- Phy class registration ---------- */
1152908d778SJames Bottomley 
sas_register_phys(struct sas_ha_struct * sas_ha)1162908d778SJames Bottomley int sas_register_phys(struct sas_ha_struct *sas_ha)
1172908d778SJames Bottomley {
1182908d778SJames Bottomley 	int i;
1192908d778SJames Bottomley 
1202908d778SJames Bottomley 	/* Now register the phys. */
1212908d778SJames Bottomley 	for (i = 0; i < sas_ha->num_phys; i++) {
1222908d778SJames Bottomley 		struct asd_sas_phy *phy = sas_ha->sas_phy[i];
1232908d778SJames Bottomley 
1242908d778SJames Bottomley 		phy->error = 0;
125f12486e0SJason Yan 		atomic_set(&phy->event_nr, 0);
1262908d778SJames Bottomley 		INIT_LIST_HEAD(&phy->port_phy_el);
127c4028958SDavid Howells 
1282908d778SJames Bottomley 		phy->port = NULL;
1292908d778SJames Bottomley 		phy->ha = sas_ha;
1302908d778SJames Bottomley 		spin_lock_init(&phy->frame_rcvd_lock);
1312908d778SJames Bottomley 		spin_lock_init(&phy->sas_prim_lock);
1322908d778SJames Bottomley 		phy->frame_rcvd_size = 0;
1332908d778SJames Bottomley 
134*1136a022SJohn Garry 		phy->phy = sas_phy_alloc(&sas_ha->shost->shost_gendev, i);
1352908d778SJames Bottomley 		if (!phy->phy)
1362908d778SJames Bottomley 			return -ENOMEM;
1372908d778SJames Bottomley 
1382908d778SJames Bottomley 		phy->phy->identify.initiator_port_protocols =
1392908d778SJames Bottomley 			phy->iproto;
1402908d778SJames Bottomley 		phy->phy->identify.target_port_protocols = phy->tproto;
1412908d778SJames Bottomley 		phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr);
1422908d778SJames Bottomley 		phy->phy->identify.phy_identifier = i;
143a01e70e5SJames Bottomley 		phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
144a01e70e5SJames Bottomley 		phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN;
145a01e70e5SJames Bottomley 		phy->phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN;
146a01e70e5SJames Bottomley 		phy->phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN;
1472908d778SJames Bottomley 		phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
1482908d778SJames Bottomley 
1492908d778SJames Bottomley 		sas_phy_add(phy->phy);
1502908d778SJames Bottomley 	}
1512908d778SJames Bottomley 
1522908d778SJames Bottomley 	return 0;
1532908d778SJames Bottomley }
1541c393b97SJason Yan 
1551c393b97SJason Yan const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS] = {
1561c393b97SJason Yan 	[PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal,
1571c393b97SJason Yan 	[PHYE_OOB_DONE] = sas_phye_oob_done,
1581c393b97SJason Yan 	[PHYE_OOB_ERROR] = sas_phye_oob_error,
1591c393b97SJason Yan 	[PHYE_SPINUP_HOLD] = sas_phye_spinup_hold,
1601c393b97SJason Yan 	[PHYE_RESUME_TIMEOUT] = sas_phye_resume_timeout,
161f12486e0SJason Yan 	[PHYE_SHUTDOWN] = sas_phye_shutdown,
1621c393b97SJason Yan };
163