226 lines · c
1/* SPDX-License-Identifier: GPL-2.0-only */2/*3 * Serial Attached SCSI (SAS) class internal header file4 *5 * Copyright (C) 2005 Adaptec, Inc. All rights reserved.6 * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>7 */8 9#ifndef _SAS_INTERNAL_H_10#define _SAS_INTERNAL_H_11 12#include <scsi/scsi.h>13#include <scsi/scsi_host.h>14#include <scsi/scsi_transport_sas.h>15#include <scsi/libsas.h>16#include <scsi/sas_ata.h>17#include <linux/pm_runtime.h>18 19#ifdef pr_fmt20#undef pr_fmt21#endif22 23#define SAS_FMT "sas: "24 25#define pr_fmt(fmt) SAS_FMT fmt26 27#define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble)28#define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0)29 30struct sas_phy_data {31 /* let reset be performed in sas_queue_work() context */32 struct sas_phy *phy;33 struct mutex event_lock;34 int hard_reset;35 int reset_result;36 struct sas_work reset_work;37 int enable;38 int enable_result;39 struct sas_work enable_work;40};41 42void sas_hash_addr(u8 *hashed, const u8 *sas_addr);43 44int sas_discover_root_expander(struct domain_device *dev);45 46int sas_ex_revalidate_domain(struct domain_device *dev);47void sas_unregister_domain_devices(struct asd_sas_port *port, int gone);48void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port);49void sas_discover_event(struct asd_sas_port *port, enum discover_event ev);50 51void sas_init_dev(struct domain_device *dev);52void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev);53 54void sas_scsi_recover_host(struct Scsi_Host *shost);55 56int sas_register_phys(struct sas_ha_struct *sas_ha);57 58struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags);59void sas_free_event(struct asd_sas_event *event);60 61struct sas_task *sas_alloc_task(gfp_t flags);62struct sas_task *sas_alloc_slow_task(gfp_t flags);63void sas_free_task(struct sas_task *task);64 65int sas_register_ports(struct sas_ha_struct *sas_ha);66void sas_unregister_ports(struct sas_ha_struct *sas_ha);67 68void sas_disable_revalidation(struct sas_ha_struct *ha);69void sas_enable_revalidation(struct sas_ha_struct *ha);70void sas_queue_deferred_work(struct sas_ha_struct *ha);71void __sas_drain_work(struct sas_ha_struct *ha);72 73void sas_deform_port(struct asd_sas_phy *phy, int gone);74 75void sas_porte_bytes_dmaed(struct work_struct *work);76void sas_porte_broadcast_rcvd(struct work_struct *work);77void sas_porte_link_reset_err(struct work_struct *work);78void sas_porte_timer_event(struct work_struct *work);79void sas_porte_hard_reset(struct work_struct *work);80bool sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw);81 82int sas_notify_lldd_dev_found(struct domain_device *);83void sas_notify_lldd_dev_gone(struct domain_device *);84 85void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,86 struct sas_rphy *rphy);87int sas_smp_phy_control(struct domain_device *dev, int phy_id,88 enum phy_func phy_func, struct sas_phy_linkrates *);89int sas_smp_get_phy_events(struct sas_phy *phy);90 91void sas_device_set_phy(struct domain_device *dev, struct sas_port *port);92struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy);93struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id);94int sas_ex_phy_discover(struct domain_device *dev, int single);95int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,96 struct smp_rps_resp *rps_resp);97int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,98 u8 *sas_addr, enum sas_device_type *type);99int sas_try_ata_reset(struct asd_sas_phy *phy);100 101void sas_free_device(struct kref *kref);102void sas_destruct_devices(struct asd_sas_port *port);103 104extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS];105extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS];106 107void sas_task_internal_done(struct sas_task *task);108void sas_task_internal_timedout(struct timer_list *t);109int sas_execute_tmf(struct domain_device *device, void *parameter,110 int para_len, int force_phy_id,111 struct sas_tmf_task *tmf);112 113#ifdef CONFIG_SCSI_SAS_HOST_SMP114extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost);115#else116static inline void sas_smp_host_handler(struct bsg_job *job,117 struct Scsi_Host *shost)118{119 shost_printk(KERN_ERR, shost,120 "Cannot send SMP to a sas host (not enabled in CONFIG)\n");121 bsg_job_done(job, -EINVAL, 0);122}123#endif124 125static inline bool sas_phy_match_dev_addr(struct domain_device *dev,126 struct ex_phy *phy)127{128 return SAS_ADDR(dev->sas_addr) == SAS_ADDR(phy->attached_sas_addr);129}130 131static inline bool sas_phy_match_port_addr(struct asd_sas_port *port,132 struct ex_phy *phy)133{134 return SAS_ADDR(port->sas_addr) == SAS_ADDR(phy->attached_sas_addr);135}136 137static inline bool sas_phy_addr_match(struct ex_phy *p1, struct ex_phy *p2)138{139 return SAS_ADDR(p1->attached_sas_addr) == SAS_ADDR(p2->attached_sas_addr);140}141 142static inline void sas_fail_probe(struct domain_device *dev, const char *func, int err)143{144 pr_warn("%s: for %s device %016llx returned %d\n",145 func, dev->parent ? "exp-attached" :146 "direct-attached",147 SAS_ADDR(dev->sas_addr), err);148 149 /*150 * If the device probe failed, the expander phy attached address151 * needs to be reset so that the phy will not be treated as flutter152 * in the next revalidation153 */154 if (dev->parent && !dev_is_expander(dev->dev_type)) {155 struct sas_phy *phy = dev->phy;156 struct domain_device *parent = dev->parent;157 struct ex_phy *ex_phy = &parent->ex_dev.ex_phy[phy->number];158 159 memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE);160 }161 162 sas_unregister_dev(dev->port, dev);163}164 165static inline void sas_fill_in_rphy(struct domain_device *dev,166 struct sas_rphy *rphy)167{168 rphy->identify.sas_address = SAS_ADDR(dev->sas_addr);169 rphy->identify.initiator_port_protocols = dev->iproto;170 rphy->identify.target_port_protocols = dev->tproto;171 switch (dev->dev_type) {172 case SAS_SATA_DEV:173 /* FIXME: need sata device type */174 case SAS_END_DEVICE:175 case SAS_SATA_PENDING:176 rphy->identify.device_type = SAS_END_DEVICE;177 break;178 case SAS_EDGE_EXPANDER_DEVICE:179 rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE;180 break;181 case SAS_FANOUT_EXPANDER_DEVICE:182 rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE;183 break;184 default:185 rphy->identify.device_type = SAS_PHY_UNUSED;186 break;187 }188}189 190static inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_device *dev)191{192 struct sas_phy *phy = p->phy;193 194 if (dev) {195 if (dev_is_sata(dev))196 phy->identify.device_type = SAS_END_DEVICE;197 else198 phy->identify.device_type = dev->dev_type;199 phy->identify.target_port_protocols = dev->tproto;200 } else {201 phy->identify.device_type = SAS_PHY_UNUSED;202 phy->identify.target_port_protocols = 0;203 }204}205 206static inline struct domain_device *sas_alloc_device(void)207{208 struct domain_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);209 210 if (dev) {211 INIT_LIST_HEAD(&dev->siblings);212 INIT_LIST_HEAD(&dev->dev_list_node);213 INIT_LIST_HEAD(&dev->disco_list_node);214 kref_init(&dev->kref);215 spin_lock_init(&dev->done_lock);216 }217 return dev;218}219 220static inline void sas_put_device(struct domain_device *dev)221{222 kref_put(&dev->kref, sas_free_device);223}224 225#endif /* _SAS_INTERNAL_H_ */226