1ba6d10abSLinus Torvalds /* SPDX-License-Identifier: GPL-2.0-only */
22908d778SJames Bottomley /*
32908d778SJames Bottomley  * Serial Attached SCSI (SAS) class internal header file
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 #ifndef _SAS_INTERNAL_H_
102908d778SJames Bottomley #define _SAS_INTERNAL_H_
112908d778SJames Bottomley 
122908d778SJames Bottomley #include <scsi/scsi.h>
132908d778SJames Bottomley #include <scsi/scsi_host.h>
142908d778SJames Bottomley #include <scsi/scsi_transport_sas.h>
152908d778SJames Bottomley #include <scsi/libsas.h>
16899fcf40SDan Williams #include <scsi/sas_ata.h>
170da7ca4cSXiang Chen #include <linux/pm_runtime.h>
182908d778SJames Bottomley 
19d188e5dbSJohn Garry #ifdef pr_fmt
20d188e5dbSJohn Garry #undef pr_fmt
21d188e5dbSJohn Garry #endif
222908d778SJames Bottomley 
23d188e5dbSJohn Garry #define SAS_FMT "sas: "
24d188e5dbSJohn Garry 
25d188e5dbSJohn Garry #define pr_fmt(fmt) SAS_FMT fmt
26d188e5dbSJohn Garry 
273a2755afSDarrick J. Wong #define TO_SAS_TASK(_scsi_cmd)  ((void *)(_scsi_cmd)->host_scribble)
283a2755afSDarrick J. Wong #define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
293a2755afSDarrick J. Wong 
300b3e09daSDan Williams struct sas_phy_data {
310b3e09daSDan Williams 	/* let reset be performed in sas_queue_work() context */
320b3e09daSDan Williams 	struct sas_phy *phy;
330b3e09daSDan Williams 	struct mutex event_lock;
340b3e09daSDan Williams 	int hard_reset;
350b3e09daSDan Williams 	int reset_result;
3622b9153fSDan Williams 	struct sas_work reset_work;
372a559f4bSDan Williams 	int enable;
382a559f4bSDan Williams 	int enable_result;
3922b9153fSDan Williams 	struct sas_work enable_work;
400b3e09daSDan Williams };
410b3e09daSDan Williams 
422908d778SJames Bottomley void sas_scsi_recover_host(struct Scsi_Host *shost);
432908d778SJames Bottomley 
445929faf3SDarrick J. Wong int  sas_register_phys(struct sas_ha_struct *sas_ha);
4588edf746SJames Bottomley 
462908d778SJames Bottomley struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags);
472908d778SJames Bottomley void sas_free_event(struct asd_sas_event *event);
482908d778SJames Bottomley 
492908d778SJames Bottomley struct sas_task *sas_alloc_task(gfp_t flags);
502908d778SJames Bottomley struct sas_task *sas_alloc_slow_task(gfp_t flags);
515d6a75a1SAhmed S. Darwish void sas_free_task(struct sas_task *task);
521c393b97SJason Yan 
531c393b97SJason Yan int  sas_register_ports(struct sas_ha_struct *sas_ha);
548e8d4364SJohn Garry void sas_unregister_ports(struct sas_ha_struct *sas_ha);
558e8d4364SJohn Garry 
568e8d4364SJohn Garry void sas_disable_revalidation(struct sas_ha_struct *ha);
578e8d4364SJohn Garry void sas_enable_revalidation(struct sas_ha_struct *ha);
582908d778SJames Bottomley void sas_queue_deferred_work(struct sas_ha_struct *ha);
592908d778SJames Bottomley void __sas_drain_work(struct sas_ha_struct *ha);
602908d778SJames Bottomley 
6187c8331fSDan Williams void sas_deform_port(struct asd_sas_phy *phy, int gone);
6287c8331fSDan Williams 
631bc35475SXiang Chen void sas_porte_bytes_dmaed(struct work_struct *work);
645d7f6d10SDan Williams void sas_porte_broadcast_rcvd(struct work_struct *work);
652908d778SJames Bottomley void sas_porte_link_reset_err(struct work_struct *work);
6690f1e10dSDan Williams void sas_porte_timer_event(struct work_struct *work);
672908d778SJames Bottomley void sas_porte_hard_reset(struct work_struct *work);
68c4028958SDavid Howells bool sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw);
69c4028958SDavid Howells 
70c4028958SDavid Howells int sas_notify_lldd_dev_found(struct domain_device *);
71c4028958SDavid Howells void sas_notify_lldd_dev_gone(struct domain_device *);
72c4028958SDavid Howells 
73a2a59faaSJohn Garry void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
742908d778SJames Bottomley 		struct sas_rphy *rphy);
752908d778SJames Bottomley int sas_smp_phy_control(struct domain_device *dev, int phy_id,
762908d778SJames Bottomley 			enum phy_func phy_func, struct sas_phy_linkrates *);
772908d778SJames Bottomley int sas_smp_get_phy_events(struct sas_phy *phy);
78651a0136SChristoph Hellwig 
79651a0136SChristoph Hellwig void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
802908d778SJames Bottomley struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
81a01e70e5SJames Bottomley struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
822908d778SJames Bottomley int sas_ex_phy_discover(struct domain_device *dev, int single);
832908d778SJames Bottomley int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
84f41a0c44SDan Williams 			    struct smp_rps_resp *rps_resp);
852908d778SJames Bottomley int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
8681c757bcSDan Williams 			     u8 *sas_addr, enum sas_device_type *type);
87354cf829SDan Williams int sas_try_ata_reset(struct asd_sas_phy *phy);
88354cf829SDan Williams 
893dafe064SDamien Le Moal void sas_free_device(struct kref *kref);
90*9181ce3cSJie Zhan void sas_destruct_devices(struct asd_sas_port *port);
91*9181ce3cSJie Zhan 
92ab526633SDan Williams extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS];
93c4028958SDavid Howells extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];
942908d778SJames Bottomley 
95735f7d2fSDan Williams void sas_task_internal_done(struct sas_task *task);
960558f33cSJason Yan void sas_task_internal_timedout(struct timer_list *t);
97735f7d2fSDan Williams int sas_execute_tmf(struct domain_device *device, void *parameter,
981c393b97SJason Yan 		    int para_len, int force_phy_id,
991c393b97SJason Yan 		    struct sas_tmf_task *tmf);
1001c393b97SJason Yan 
1014aef43b2SJohn Garry #ifdef CONFIG_SCSI_SAS_HOST_SMP
1024aef43b2SJohn Garry extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost);
103001ec7f8SJohn Garry #else
sas_smp_host_handler(struct bsg_job * job,struct Scsi_Host * shost)104001ec7f8SJohn Garry static inline void sas_smp_host_handler(struct bsg_job *job,
105001ec7f8SJohn Garry 		struct Scsi_Host *shost)
1064aef43b2SJohn Garry {
107b98e66faSJames Bottomley 	shost_printk(KERN_ERR, shost,
108651a0136SChristoph Hellwig 		"Cannot send SMP to a sas host (not enabled in CONFIG)\n");
109b98e66faSJames Bottomley 	bsg_job_done(job, -EINVAL, 0);
110651a0136SChristoph Hellwig }
111651a0136SChristoph Hellwig #endif
112b98e66faSJames Bottomley 
sas_phy_match_dev_addr(struct domain_device * dev,struct ex_phy * phy)113b98e66faSJames Bottomley static inline bool sas_phy_match_dev_addr(struct domain_device *dev,
114b98e66faSJames Bottomley 					 struct ex_phy *phy)
115651a0136SChristoph Hellwig {
116b98e66faSJames Bottomley 	return SAS_ADDR(dev->sas_addr) == SAS_ADDR(phy->attached_sas_addr);
117b98e66faSJames Bottomley }
118b98e66faSJames Bottomley 
sas_phy_match_port_addr(struct asd_sas_port * port,struct ex_phy * phy)119773792e4SJason Yan static inline bool sas_phy_match_port_addr(struct asd_sas_port *port,
120773792e4SJason Yan 					   struct ex_phy *phy)
121773792e4SJason Yan {
122773792e4SJason Yan 	return SAS_ADDR(port->sas_addr) == SAS_ADDR(phy->attached_sas_addr);
123773792e4SJason Yan }
124773792e4SJason Yan 
sas_phy_addr_match(struct ex_phy * p1,struct ex_phy * p2)125773792e4SJason Yan static inline bool sas_phy_addr_match(struct ex_phy *p1, struct ex_phy *p2)
126773792e4SJason Yan {
127773792e4SJason Yan 	return  SAS_ADDR(p1->attached_sas_addr) == SAS_ADDR(p2->attached_sas_addr);
128773792e4SJason Yan }
129773792e4SJason Yan 
sas_fail_probe(struct domain_device * dev,const char * func,int err)130773792e4SJason Yan static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err)
131773792e4SJason Yan {
132773792e4SJason Yan 	pr_warn("%s: for %s device %016llx returned %d\n",
133773792e4SJason Yan 		func, dev->parent ? "exp-attached" :
134773792e4SJason Yan 		"direct-attached",
135773792e4SJason Yan 		SAS_ADDR(dev->sas_addr), err);
1369508a66fSDan Williams 	sas_unregister_dev(dev->port, dev);
1379508a66fSDan Williams }
138b3e3d4c6SJohn Garry 
sas_fill_in_rphy(struct domain_device * dev,struct sas_rphy * rphy)1399508a66fSDan Williams static inline void sas_fill_in_rphy(struct domain_device *dev,
1409508a66fSDan Williams 				    struct sas_rphy *rphy)
1419508a66fSDan Williams {
1429508a66fSDan Williams 	rphy->identify.sas_address = SAS_ADDR(dev->sas_addr);
1439508a66fSDan Williams 	rphy->identify.initiator_port_protocols = dev->iproto;
1449508a66fSDan Williams 	rphy->identify.target_port_protocols = dev->tproto;
1452908d778SJames Bottomley 	switch (dev->dev_type) {
1462908d778SJames Bottomley 	case SAS_SATA_DEV:
1472908d778SJames Bottomley 		/* FIXME: need sata device type */
1482908d778SJames Bottomley 	case SAS_END_DEVICE:
1492908d778SJames Bottomley 	case SAS_SATA_PENDING:
1502908d778SJames Bottomley 		rphy->identify.device_type = SAS_END_DEVICE;
1512908d778SJames Bottomley 		break;
152aa9f8328SJames Bottomley 	case SAS_EDGE_EXPANDER_DEVICE:
1532908d778SJames Bottomley 		rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE;
154aa9f8328SJames Bottomley 		break;
155aa9f8328SJames Bottomley 	case SAS_FANOUT_EXPANDER_DEVICE:
1562908d778SJames Bottomley 		rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE;
1572908d778SJames Bottomley 		break;
158aa9f8328SJames Bottomley 	default:
1592908d778SJames Bottomley 		rphy->identify.device_type = SAS_PHY_UNUSED;
1602908d778SJames Bottomley 		break;
161aa9f8328SJames Bottomley 	}
1622908d778SJames Bottomley }
1632908d778SJames Bottomley 
sas_phy_set_target(struct asd_sas_phy * p,struct domain_device * dev)1642908d778SJames Bottomley static inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_device *dev)
1652908d778SJames Bottomley {
1662908d778SJames Bottomley 	struct sas_phy *phy = p->phy;
1672908d778SJames Bottomley 
1682908d778SJames Bottomley 	if (dev) {
1692908d778SJames Bottomley 		if (dev_is_sata(dev))
170899fcf40SDan Williams 			phy->identify.device_type = SAS_END_DEVICE;
171899fcf40SDan Williams 		else
172899fcf40SDan Williams 			phy->identify.device_type = dev->dev_type;
173899fcf40SDan Williams 		phy->identify.target_port_protocols = dev->tproto;
174899fcf40SDan Williams 	} else {
175899fcf40SDan Williams 		phy->identify.device_type = SAS_PHY_UNUSED;
176899fcf40SDan Williams 		phy->identify.target_port_protocols = 0;
177899fcf40SDan Williams 	}
178899fcf40SDan Williams }
179899fcf40SDan Williams 
sas_add_parent_port(struct domain_device * dev,int phy_id)180899fcf40SDan Williams static inline void sas_add_parent_port(struct domain_device *dev, int phy_id)
181899fcf40SDan Williams {
182899fcf40SDan Williams 	struct expander_device *ex = &dev->ex_dev;
183899fcf40SDan Williams 	struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
184899fcf40SDan Williams 
185899fcf40SDan Williams 	if (!ex->parent_port) {
1862908d778SJames Bottomley 		ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id);
1872908d778SJames Bottomley 		/* FIXME: error handling */
1882908d778SJames Bottomley 		BUG_ON(!ex->parent_port);
1892908d778SJames Bottomley 		BUG_ON(sas_port_add(ex->parent_port));
1902908d778SJames Bottomley 		sas_port_mark_backlink(ex->parent_port);
1912908d778SJames Bottomley 	}
1922908d778SJames Bottomley 	sas_port_add_phy(ex->parent_port, ex_phy->phy);
1932908d778SJames Bottomley }
1942908d778SJames Bottomley 
sas_alloc_device(void)1952908d778SJames Bottomley static inline struct domain_device *sas_alloc_device(void)
1962908d778SJames Bottomley {
1972908d778SJames Bottomley 	struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
1982908d778SJames Bottomley 
1992908d778SJames Bottomley 	if (dev) {
2002908d778SJames Bottomley 		INIT_LIST_HEAD(&dev->siblings);
201735f7d2fSDan Williams 		INIT_LIST_HEAD(&dev->dev_list_node);
202735f7d2fSDan Williams 		INIT_LIST_HEAD(&dev->disco_list_node);
203735f7d2fSDan Williams 		kref_init(&dev->kref);
204735f7d2fSDan Williams 		spin_lock_init(&dev->done_lock);
205735f7d2fSDan Williams 	}
206735f7d2fSDan Williams 	return dev;
207735f7d2fSDan Williams }
20887c8331fSDan Williams 
sas_put_device(struct domain_device * dev)209735f7d2fSDan Williams static inline void sas_put_device(struct domain_device *dev)
2109095a64aSDan Williams {
211735f7d2fSDan Williams 	kref_put(&dev->kref, sas_free_device);
212735f7d2fSDan Williams }
213735f7d2fSDan Williams 
214735f7d2fSDan Williams #endif /* _SAS_INTERNAL_H_ */
215735f7d2fSDan Williams