162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Serial Attached SCSI (SAS) class internal header file
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
662306a36Sopenharmony_ci * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#ifndef _SAS_INTERNAL_H_
1062306a36Sopenharmony_ci#define _SAS_INTERNAL_H_
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <scsi/scsi.h>
1362306a36Sopenharmony_ci#include <scsi/scsi_host.h>
1462306a36Sopenharmony_ci#include <scsi/scsi_transport_sas.h>
1562306a36Sopenharmony_ci#include <scsi/libsas.h>
1662306a36Sopenharmony_ci#include <scsi/sas_ata.h>
1762306a36Sopenharmony_ci#include <linux/pm_runtime.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#ifdef pr_fmt
2062306a36Sopenharmony_ci#undef pr_fmt
2162306a36Sopenharmony_ci#endif
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define SAS_FMT "sas: "
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci#define pr_fmt(fmt) SAS_FMT fmt
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#define TO_SAS_TASK(_scsi_cmd)  ((void *)(_scsi_cmd)->host_scribble)
2862306a36Sopenharmony_ci#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct sas_phy_data {
3162306a36Sopenharmony_ci	/* let reset be performed in sas_queue_work() context */
3262306a36Sopenharmony_ci	struct sas_phy *phy;
3362306a36Sopenharmony_ci	struct mutex event_lock;
3462306a36Sopenharmony_ci	int hard_reset;
3562306a36Sopenharmony_ci	int reset_result;
3662306a36Sopenharmony_ci	struct sas_work reset_work;
3762306a36Sopenharmony_ci	int enable;
3862306a36Sopenharmony_ci	int enable_result;
3962306a36Sopenharmony_ci	struct sas_work enable_work;
4062306a36Sopenharmony_ci};
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_civoid sas_scsi_recover_host(struct Scsi_Host *shost);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ciint  sas_register_phys(struct sas_ha_struct *sas_ha);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_cistruct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags);
4762306a36Sopenharmony_civoid sas_free_event(struct asd_sas_event *event);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistruct sas_task *sas_alloc_task(gfp_t flags);
5062306a36Sopenharmony_cistruct sas_task *sas_alloc_slow_task(gfp_t flags);
5162306a36Sopenharmony_civoid sas_free_task(struct sas_task *task);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ciint  sas_register_ports(struct sas_ha_struct *sas_ha);
5462306a36Sopenharmony_civoid sas_unregister_ports(struct sas_ha_struct *sas_ha);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_civoid sas_disable_revalidation(struct sas_ha_struct *ha);
5762306a36Sopenharmony_civoid sas_enable_revalidation(struct sas_ha_struct *ha);
5862306a36Sopenharmony_civoid sas_queue_deferred_work(struct sas_ha_struct *ha);
5962306a36Sopenharmony_civoid __sas_drain_work(struct sas_ha_struct *ha);
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_civoid sas_deform_port(struct asd_sas_phy *phy, int gone);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_civoid sas_porte_bytes_dmaed(struct work_struct *work);
6462306a36Sopenharmony_civoid sas_porte_broadcast_rcvd(struct work_struct *work);
6562306a36Sopenharmony_civoid sas_porte_link_reset_err(struct work_struct *work);
6662306a36Sopenharmony_civoid sas_porte_timer_event(struct work_struct *work);
6762306a36Sopenharmony_civoid sas_porte_hard_reset(struct work_struct *work);
6862306a36Sopenharmony_cibool sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciint sas_notify_lldd_dev_found(struct domain_device *);
7162306a36Sopenharmony_civoid sas_notify_lldd_dev_gone(struct domain_device *);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_civoid sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
7462306a36Sopenharmony_ci		struct sas_rphy *rphy);
7562306a36Sopenharmony_ciint sas_smp_phy_control(struct domain_device *dev, int phy_id,
7662306a36Sopenharmony_ci			enum phy_func phy_func, struct sas_phy_linkrates *);
7762306a36Sopenharmony_ciint sas_smp_get_phy_events(struct sas_phy *phy);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_civoid sas_device_set_phy(struct domain_device *dev, struct sas_port *port);
8062306a36Sopenharmony_cistruct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);
8162306a36Sopenharmony_cistruct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);
8262306a36Sopenharmony_ciint sas_ex_phy_discover(struct domain_device *dev, int single);
8362306a36Sopenharmony_ciint sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
8462306a36Sopenharmony_ci			    struct smp_rps_resp *rps_resp);
8562306a36Sopenharmony_ciint sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
8662306a36Sopenharmony_ci			     u8 *sas_addr, enum sas_device_type *type);
8762306a36Sopenharmony_ciint sas_try_ata_reset(struct asd_sas_phy *phy);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_civoid sas_free_device(struct kref *kref);
9062306a36Sopenharmony_civoid sas_destruct_devices(struct asd_sas_port *port);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciextern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS];
9362306a36Sopenharmony_ciextern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_civoid sas_task_internal_done(struct sas_task *task);
9662306a36Sopenharmony_civoid sas_task_internal_timedout(struct timer_list *t);
9762306a36Sopenharmony_ciint sas_execute_tmf(struct domain_device *device, void *parameter,
9862306a36Sopenharmony_ci		    int para_len, int force_phy_id,
9962306a36Sopenharmony_ci		    struct sas_tmf_task *tmf);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci#ifdef CONFIG_SCSI_SAS_HOST_SMP
10262306a36Sopenharmony_ciextern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost);
10362306a36Sopenharmony_ci#else
10462306a36Sopenharmony_cistatic inline void sas_smp_host_handler(struct bsg_job *job,
10562306a36Sopenharmony_ci		struct Scsi_Host *shost)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	shost_printk(KERN_ERR, shost,
10862306a36Sopenharmony_ci		"Cannot send SMP to a sas host (not enabled in CONFIG)\n");
10962306a36Sopenharmony_ci	bsg_job_done(job, -EINVAL, 0);
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci#endif
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic inline bool sas_phy_match_dev_addr(struct domain_device *dev,
11462306a36Sopenharmony_ci					 struct ex_phy *phy)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	return SAS_ADDR(dev->sas_addr) == SAS_ADDR(phy->attached_sas_addr);
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic inline bool sas_phy_match_port_addr(struct asd_sas_port *port,
12062306a36Sopenharmony_ci					   struct ex_phy *phy)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	return SAS_ADDR(port->sas_addr) == SAS_ADDR(phy->attached_sas_addr);
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic inline bool sas_phy_addr_match(struct ex_phy *p1, struct ex_phy *p2)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	return  SAS_ADDR(p1->attached_sas_addr) == SAS_ADDR(p2->attached_sas_addr);
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cistatic inline void sas_fail_probe(struct domain_device *dev, const char *func, int err)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	pr_warn("%s: for %s device %016llx returned %d\n",
13362306a36Sopenharmony_ci		func, dev->parent ? "exp-attached" :
13462306a36Sopenharmony_ci		"direct-attached",
13562306a36Sopenharmony_ci		SAS_ADDR(dev->sas_addr), err);
13662306a36Sopenharmony_ci	sas_unregister_dev(dev->port, dev);
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic inline void sas_fill_in_rphy(struct domain_device *dev,
14062306a36Sopenharmony_ci				    struct sas_rphy *rphy)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	rphy->identify.sas_address = SAS_ADDR(dev->sas_addr);
14362306a36Sopenharmony_ci	rphy->identify.initiator_port_protocols = dev->iproto;
14462306a36Sopenharmony_ci	rphy->identify.target_port_protocols = dev->tproto;
14562306a36Sopenharmony_ci	switch (dev->dev_type) {
14662306a36Sopenharmony_ci	case SAS_SATA_DEV:
14762306a36Sopenharmony_ci		/* FIXME: need sata device type */
14862306a36Sopenharmony_ci	case SAS_END_DEVICE:
14962306a36Sopenharmony_ci	case SAS_SATA_PENDING:
15062306a36Sopenharmony_ci		rphy->identify.device_type = SAS_END_DEVICE;
15162306a36Sopenharmony_ci		break;
15262306a36Sopenharmony_ci	case SAS_EDGE_EXPANDER_DEVICE:
15362306a36Sopenharmony_ci		rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE;
15462306a36Sopenharmony_ci		break;
15562306a36Sopenharmony_ci	case SAS_FANOUT_EXPANDER_DEVICE:
15662306a36Sopenharmony_ci		rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE;
15762306a36Sopenharmony_ci		break;
15862306a36Sopenharmony_ci	default:
15962306a36Sopenharmony_ci		rphy->identify.device_type = SAS_PHY_UNUSED;
16062306a36Sopenharmony_ci		break;
16162306a36Sopenharmony_ci	}
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_cistatic inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_device *dev)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	struct sas_phy *phy = p->phy;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	if (dev) {
16962306a36Sopenharmony_ci		if (dev_is_sata(dev))
17062306a36Sopenharmony_ci			phy->identify.device_type = SAS_END_DEVICE;
17162306a36Sopenharmony_ci		else
17262306a36Sopenharmony_ci			phy->identify.device_type = dev->dev_type;
17362306a36Sopenharmony_ci		phy->identify.target_port_protocols = dev->tproto;
17462306a36Sopenharmony_ci	} else {
17562306a36Sopenharmony_ci		phy->identify.device_type = SAS_PHY_UNUSED;
17662306a36Sopenharmony_ci		phy->identify.target_port_protocols = 0;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_cistatic inline void sas_add_parent_port(struct domain_device *dev, int phy_id)
18162306a36Sopenharmony_ci{
18262306a36Sopenharmony_ci	struct expander_device *ex = &dev->ex_dev;
18362306a36Sopenharmony_ci	struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (!ex->parent_port) {
18662306a36Sopenharmony_ci		ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id);
18762306a36Sopenharmony_ci		/* FIXME: error handling */
18862306a36Sopenharmony_ci		BUG_ON(!ex->parent_port);
18962306a36Sopenharmony_ci		BUG_ON(sas_port_add(ex->parent_port));
19062306a36Sopenharmony_ci		sas_port_mark_backlink(ex->parent_port);
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci	sas_port_add_phy(ex->parent_port, ex_phy->phy);
19362306a36Sopenharmony_ci}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic inline struct domain_device *sas_alloc_device(void)
19662306a36Sopenharmony_ci{
19762306a36Sopenharmony_ci	struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (dev) {
20062306a36Sopenharmony_ci		INIT_LIST_HEAD(&dev->siblings);
20162306a36Sopenharmony_ci		INIT_LIST_HEAD(&dev->dev_list_node);
20262306a36Sopenharmony_ci		INIT_LIST_HEAD(&dev->disco_list_node);
20362306a36Sopenharmony_ci		kref_init(&dev->kref);
20462306a36Sopenharmony_ci		spin_lock_init(&dev->done_lock);
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci	return dev;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic inline void sas_put_device(struct domain_device *dev)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	kref_put(&dev->kref, sas_free_device);
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci#endif /* _SAS_INTERNAL_H_ */
215