1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
2 | /* |
3 | * Serial Attached SCSI (SAS) class internal header file |
4 | * |
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_fmt |
20 | #undef pr_fmt |
21 | #endif |
22 | |
23 | #define SAS_FMT "sas: " |
24 | |
25 | #define pr_fmt(fmt) SAS_FMT fmt |
26 | |
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 | |
30 | struct 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 | |
42 | void sas_hash_addr(u8 *hashed, const u8 *sas_addr); |
43 | |
44 | int sas_discover_root_expander(struct domain_device *dev); |
45 | |
46 | int sas_ex_revalidate_domain(struct domain_device *dev); |
47 | void sas_unregister_domain_devices(struct asd_sas_port *port, int gone); |
48 | void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port); |
49 | void sas_discover_event(struct asd_sas_port *port, enum discover_event ev); |
50 | |
51 | void sas_init_dev(struct domain_device *dev); |
52 | void sas_unregister_dev(struct asd_sas_port *port, struct domain_device *dev); |
53 | |
54 | void sas_scsi_recover_host(struct Scsi_Host *shost); |
55 | |
56 | int sas_register_phys(struct sas_ha_struct *sas_ha); |
57 | |
58 | struct asd_sas_event *sas_alloc_event(struct asd_sas_phy *phy, gfp_t gfp_flags); |
59 | void sas_free_event(struct asd_sas_event *event); |
60 | |
61 | struct sas_task *sas_alloc_task(gfp_t flags); |
62 | struct sas_task *sas_alloc_slow_task(gfp_t flags); |
63 | void sas_free_task(struct sas_task *task); |
64 | |
65 | int sas_register_ports(struct sas_ha_struct *sas_ha); |
66 | void sas_unregister_ports(struct sas_ha_struct *sas_ha); |
67 | |
68 | void sas_disable_revalidation(struct sas_ha_struct *ha); |
69 | void sas_enable_revalidation(struct sas_ha_struct *ha); |
70 | void sas_queue_deferred_work(struct sas_ha_struct *ha); |
71 | void __sas_drain_work(struct sas_ha_struct *ha); |
72 | |
73 | void sas_deform_port(struct asd_sas_phy *phy, int gone); |
74 | |
75 | void sas_porte_bytes_dmaed(struct work_struct *work); |
76 | void sas_porte_broadcast_rcvd(struct work_struct *work); |
77 | void sas_porte_link_reset_err(struct work_struct *work); |
78 | void sas_porte_timer_event(struct work_struct *work); |
79 | void sas_porte_hard_reset(struct work_struct *work); |
80 | bool sas_queue_work(struct sas_ha_struct *ha, struct sas_work *sw); |
81 | |
82 | int sas_notify_lldd_dev_found(struct domain_device *); |
83 | void sas_notify_lldd_dev_gone(struct domain_device *); |
84 | |
85 | void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, |
86 | struct sas_rphy *rphy); |
87 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, |
88 | enum phy_func phy_func, struct sas_phy_linkrates *); |
89 | int sas_smp_get_phy_events(struct sas_phy *phy); |
90 | |
91 | void sas_device_set_phy(struct domain_device *dev, struct sas_port *port); |
92 | struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); |
93 | struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id); |
94 | int sas_ex_phy_discover(struct domain_device *dev, int single); |
95 | int sas_get_report_phy_sata(struct domain_device *dev, int phy_id, |
96 | struct smp_rps_resp *rps_resp); |
97 | int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id, |
98 | u8 *sas_addr, enum sas_device_type *type); |
99 | int sas_try_ata_reset(struct asd_sas_phy *phy); |
100 | |
101 | void sas_free_device(struct kref *kref); |
102 | void sas_destruct_devices(struct asd_sas_port *port); |
103 | |
104 | extern const work_func_t sas_phy_event_fns[PHY_NUM_EVENTS]; |
105 | extern const work_func_t sas_port_event_fns[PORT_NUM_EVENTS]; |
106 | |
107 | void sas_task_internal_done(struct sas_task *task); |
108 | void sas_task_internal_timedout(struct timer_list *t); |
109 | int 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_SMP |
114 | extern void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost); |
115 | #else |
116 | static 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 | #endif |
124 | |
125 | static 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 | |
131 | static 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 | |
137 | static 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 | |
142 | static 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 | sas_unregister_dev(port: dev->port, dev); |
149 | } |
150 | |
151 | static inline void sas_fill_in_rphy(struct domain_device *dev, |
152 | struct sas_rphy *rphy) |
153 | { |
154 | rphy->identify.sas_address = SAS_ADDR(dev->sas_addr); |
155 | rphy->identify.initiator_port_protocols = dev->iproto; |
156 | rphy->identify.target_port_protocols = dev->tproto; |
157 | switch (dev->dev_type) { |
158 | case SAS_SATA_DEV: |
159 | /* FIXME: need sata device type */ |
160 | case SAS_END_DEVICE: |
161 | case SAS_SATA_PENDING: |
162 | rphy->identify.device_type = SAS_END_DEVICE; |
163 | break; |
164 | case SAS_EDGE_EXPANDER_DEVICE: |
165 | rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE; |
166 | break; |
167 | case SAS_FANOUT_EXPANDER_DEVICE: |
168 | rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE; |
169 | break; |
170 | default: |
171 | rphy->identify.device_type = SAS_PHY_UNUSED; |
172 | break; |
173 | } |
174 | } |
175 | |
176 | static inline void sas_phy_set_target(struct asd_sas_phy *p, struct domain_device *dev) |
177 | { |
178 | struct sas_phy *phy = p->phy; |
179 | |
180 | if (dev) { |
181 | if (dev_is_sata(dev)) |
182 | phy->identify.device_type = SAS_END_DEVICE; |
183 | else |
184 | phy->identify.device_type = dev->dev_type; |
185 | phy->identify.target_port_protocols = dev->tproto; |
186 | } else { |
187 | phy->identify.device_type = SAS_PHY_UNUSED; |
188 | phy->identify.target_port_protocols = 0; |
189 | } |
190 | } |
191 | |
192 | static inline void sas_add_parent_port(struct domain_device *dev, int phy_id) |
193 | { |
194 | struct expander_device *ex = &dev->ex_dev; |
195 | struct ex_phy *ex_phy = &ex->ex_phy[phy_id]; |
196 | |
197 | if (!ex->parent_port) { |
198 | ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id); |
199 | /* FIXME: error handling */ |
200 | BUG_ON(!ex->parent_port); |
201 | BUG_ON(sas_port_add(ex->parent_port)); |
202 | sas_port_mark_backlink(ex->parent_port); |
203 | } |
204 | sas_port_add_phy(ex->parent_port, ex_phy->phy); |
205 | } |
206 | |
207 | static inline struct domain_device *sas_alloc_device(void) |
208 | { |
209 | struct domain_device *dev = kzalloc(size: sizeof(*dev), GFP_KERNEL); |
210 | |
211 | if (dev) { |
212 | INIT_LIST_HEAD(list: &dev->siblings); |
213 | INIT_LIST_HEAD(list: &dev->dev_list_node); |
214 | INIT_LIST_HEAD(list: &dev->disco_list_node); |
215 | kref_init(kref: &dev->kref); |
216 | spin_lock_init(&dev->done_lock); |
217 | } |
218 | return dev; |
219 | } |
220 | |
221 | static inline void sas_put_device(struct domain_device *dev) |
222 | { |
223 | kref_put(kref: &dev->kref, release: sas_free_device); |
224 | } |
225 | |
226 | #endif /* _SAS_INTERNAL_H_ */ |
227 | |