xref: /OK3568_Linux_fs/kernel/drivers/scsi/libsas/sas_expander.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Serial Attached SCSI (SAS) Expander discovery and configuration
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2005 Adaptec, Inc.  All rights reserved.
6*4882a593Smuzhiyun  * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * This file is licensed under GPLv2.
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include <linux/scatterlist.h>
12*4882a593Smuzhiyun #include <linux/blkdev.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <asm/unaligned.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "sas_internal.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <scsi/sas_ata.h>
19*4882a593Smuzhiyun #include <scsi/scsi_transport.h>
20*4882a593Smuzhiyun #include <scsi/scsi_transport_sas.h>
21*4882a593Smuzhiyun #include "../scsi_sas_internal.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun static int sas_discover_expander(struct domain_device *dev);
24*4882a593Smuzhiyun static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr);
25*4882a593Smuzhiyun static int sas_configure_phy(struct domain_device *dev, int phy_id,
26*4882a593Smuzhiyun 			     u8 *sas_addr, int include);
27*4882a593Smuzhiyun static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr);
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun /* ---------- SMP task management ---------- */
30*4882a593Smuzhiyun 
smp_task_timedout(struct timer_list * t)31*4882a593Smuzhiyun static void smp_task_timedout(struct timer_list *t)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun 	struct sas_task_slow *slow = from_timer(slow, t, timer);
34*4882a593Smuzhiyun 	struct sas_task *task = slow->task;
35*4882a593Smuzhiyun 	unsigned long flags;
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun 	spin_lock_irqsave(&task->task_state_lock, flags);
38*4882a593Smuzhiyun 	if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
39*4882a593Smuzhiyun 		task->task_state_flags |= SAS_TASK_STATE_ABORTED;
40*4882a593Smuzhiyun 		complete(&task->slow_task->completion);
41*4882a593Smuzhiyun 	}
42*4882a593Smuzhiyun 	spin_unlock_irqrestore(&task->task_state_lock, flags);
43*4882a593Smuzhiyun }
44*4882a593Smuzhiyun 
smp_task_done(struct sas_task * task)45*4882a593Smuzhiyun static void smp_task_done(struct sas_task *task)
46*4882a593Smuzhiyun {
47*4882a593Smuzhiyun 	del_timer(&task->slow_task->timer);
48*4882a593Smuzhiyun 	complete(&task->slow_task->completion);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun /* Give it some long enough timeout. In seconds. */
52*4882a593Smuzhiyun #define SMP_TIMEOUT 10
53*4882a593Smuzhiyun 
smp_execute_task_sg(struct domain_device * dev,struct scatterlist * req,struct scatterlist * resp)54*4882a593Smuzhiyun static int smp_execute_task_sg(struct domain_device *dev,
55*4882a593Smuzhiyun 		struct scatterlist *req, struct scatterlist *resp)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	int res, retry;
58*4882a593Smuzhiyun 	struct sas_task *task = NULL;
59*4882a593Smuzhiyun 	struct sas_internal *i =
60*4882a593Smuzhiyun 		to_sas_internal(dev->port->ha->core.shost->transportt);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	mutex_lock(&dev->ex_dev.cmd_mutex);
63*4882a593Smuzhiyun 	for (retry = 0; retry < 3; retry++) {
64*4882a593Smuzhiyun 		if (test_bit(SAS_DEV_GONE, &dev->state)) {
65*4882a593Smuzhiyun 			res = -ECOMM;
66*4882a593Smuzhiyun 			break;
67*4882a593Smuzhiyun 		}
68*4882a593Smuzhiyun 
69*4882a593Smuzhiyun 		task = sas_alloc_slow_task(GFP_KERNEL);
70*4882a593Smuzhiyun 		if (!task) {
71*4882a593Smuzhiyun 			res = -ENOMEM;
72*4882a593Smuzhiyun 			break;
73*4882a593Smuzhiyun 		}
74*4882a593Smuzhiyun 		task->dev = dev;
75*4882a593Smuzhiyun 		task->task_proto = dev->tproto;
76*4882a593Smuzhiyun 		task->smp_task.smp_req = *req;
77*4882a593Smuzhiyun 		task->smp_task.smp_resp = *resp;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 		task->task_done = smp_task_done;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 		task->slow_task->timer.function = smp_task_timedout;
82*4882a593Smuzhiyun 		task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
83*4882a593Smuzhiyun 		add_timer(&task->slow_task->timer);
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 		res = i->dft->lldd_execute_task(task, GFP_KERNEL);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 		if (res) {
88*4882a593Smuzhiyun 			del_timer_sync(&task->slow_task->timer);
89*4882a593Smuzhiyun 			pr_notice("executing SMP task failed:%d\n", res);
90*4882a593Smuzhiyun 			break;
91*4882a593Smuzhiyun 		}
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 		wait_for_completion(&task->slow_task->completion);
94*4882a593Smuzhiyun 		res = -ECOMM;
95*4882a593Smuzhiyun 		if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) {
96*4882a593Smuzhiyun 			pr_notice("smp task timed out or aborted\n");
97*4882a593Smuzhiyun 			i->dft->lldd_abort_task(task);
98*4882a593Smuzhiyun 			if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) {
99*4882a593Smuzhiyun 				pr_notice("SMP task aborted and not done\n");
100*4882a593Smuzhiyun 				break;
101*4882a593Smuzhiyun 			}
102*4882a593Smuzhiyun 		}
103*4882a593Smuzhiyun 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
104*4882a593Smuzhiyun 		    task->task_status.stat == SAM_STAT_GOOD) {
105*4882a593Smuzhiyun 			res = 0;
106*4882a593Smuzhiyun 			break;
107*4882a593Smuzhiyun 		}
108*4882a593Smuzhiyun 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
109*4882a593Smuzhiyun 		    task->task_status.stat == SAS_DATA_UNDERRUN) {
110*4882a593Smuzhiyun 			/* no error, but return the number of bytes of
111*4882a593Smuzhiyun 			 * underrun */
112*4882a593Smuzhiyun 			res = task->task_status.residual;
113*4882a593Smuzhiyun 			break;
114*4882a593Smuzhiyun 		}
115*4882a593Smuzhiyun 		if (task->task_status.resp == SAS_TASK_COMPLETE &&
116*4882a593Smuzhiyun 		    task->task_status.stat == SAS_DATA_OVERRUN) {
117*4882a593Smuzhiyun 			res = -EMSGSIZE;
118*4882a593Smuzhiyun 			break;
119*4882a593Smuzhiyun 		}
120*4882a593Smuzhiyun 		if (task->task_status.resp == SAS_TASK_UNDELIVERED &&
121*4882a593Smuzhiyun 		    task->task_status.stat == SAS_DEVICE_UNKNOWN)
122*4882a593Smuzhiyun 			break;
123*4882a593Smuzhiyun 		else {
124*4882a593Smuzhiyun 			pr_notice("%s: task to dev %016llx response: 0x%x status 0x%x\n",
125*4882a593Smuzhiyun 				  __func__,
126*4882a593Smuzhiyun 				  SAS_ADDR(dev->sas_addr),
127*4882a593Smuzhiyun 				  task->task_status.resp,
128*4882a593Smuzhiyun 				  task->task_status.stat);
129*4882a593Smuzhiyun 			sas_free_task(task);
130*4882a593Smuzhiyun 			task = NULL;
131*4882a593Smuzhiyun 		}
132*4882a593Smuzhiyun 	}
133*4882a593Smuzhiyun 	mutex_unlock(&dev->ex_dev.cmd_mutex);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	BUG_ON(retry == 3 && task != NULL);
136*4882a593Smuzhiyun 	sas_free_task(task);
137*4882a593Smuzhiyun 	return res;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun 
smp_execute_task(struct domain_device * dev,void * req,int req_size,void * resp,int resp_size)140*4882a593Smuzhiyun static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
141*4882a593Smuzhiyun 			    void *resp, int resp_size)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	struct scatterlist req_sg;
144*4882a593Smuzhiyun 	struct scatterlist resp_sg;
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	sg_init_one(&req_sg, req, req_size);
147*4882a593Smuzhiyun 	sg_init_one(&resp_sg, resp, resp_size);
148*4882a593Smuzhiyun 	return smp_execute_task_sg(dev, &req_sg, &resp_sg);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun /* ---------- Allocations ---------- */
152*4882a593Smuzhiyun 
alloc_smp_req(int size)153*4882a593Smuzhiyun static inline void *alloc_smp_req(int size)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	u8 *p = kzalloc(size, GFP_KERNEL);
156*4882a593Smuzhiyun 	if (p)
157*4882a593Smuzhiyun 		p[0] = SMP_REQUEST;
158*4882a593Smuzhiyun 	return p;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
alloc_smp_resp(int size)161*4882a593Smuzhiyun static inline void *alloc_smp_resp(int size)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	return kzalloc(size, GFP_KERNEL);
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
sas_route_char(struct domain_device * dev,struct ex_phy * phy)166*4882a593Smuzhiyun static char sas_route_char(struct domain_device *dev, struct ex_phy *phy)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun 	switch (phy->routing_attr) {
169*4882a593Smuzhiyun 	case TABLE_ROUTING:
170*4882a593Smuzhiyun 		if (dev->ex_dev.t2t_supp)
171*4882a593Smuzhiyun 			return 'U';
172*4882a593Smuzhiyun 		else
173*4882a593Smuzhiyun 			return 'T';
174*4882a593Smuzhiyun 	case DIRECT_ROUTING:
175*4882a593Smuzhiyun 		return 'D';
176*4882a593Smuzhiyun 	case SUBTRACTIVE_ROUTING:
177*4882a593Smuzhiyun 		return 'S';
178*4882a593Smuzhiyun 	default:
179*4882a593Smuzhiyun 		return '?';
180*4882a593Smuzhiyun 	}
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun 
to_dev_type(struct discover_resp * dr)183*4882a593Smuzhiyun static enum sas_device_type to_dev_type(struct discover_resp *dr)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	/* This is detecting a failure to transmit initial dev to host
186*4882a593Smuzhiyun 	 * FIS as described in section J.5 of sas-2 r16
187*4882a593Smuzhiyun 	 */
188*4882a593Smuzhiyun 	if (dr->attached_dev_type == SAS_PHY_UNUSED && dr->attached_sata_dev &&
189*4882a593Smuzhiyun 	    dr->linkrate >= SAS_LINK_RATE_1_5_GBPS)
190*4882a593Smuzhiyun 		return SAS_SATA_PENDING;
191*4882a593Smuzhiyun 	else
192*4882a593Smuzhiyun 		return dr->attached_dev_type;
193*4882a593Smuzhiyun }
194*4882a593Smuzhiyun 
sas_set_ex_phy(struct domain_device * dev,int phy_id,void * rsp)195*4882a593Smuzhiyun static void sas_set_ex_phy(struct domain_device *dev, int phy_id, void *rsp)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	enum sas_device_type dev_type;
198*4882a593Smuzhiyun 	enum sas_linkrate linkrate;
199*4882a593Smuzhiyun 	u8 sas_addr[SAS_ADDR_SIZE];
200*4882a593Smuzhiyun 	struct smp_resp *resp = rsp;
201*4882a593Smuzhiyun 	struct discover_resp *dr = &resp->disc;
202*4882a593Smuzhiyun 	struct sas_ha_struct *ha = dev->port->ha;
203*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
204*4882a593Smuzhiyun 	struct ex_phy *phy = &ex->ex_phy[phy_id];
205*4882a593Smuzhiyun 	struct sas_rphy *rphy = dev->rphy;
206*4882a593Smuzhiyun 	bool new_phy = !phy->phy;
207*4882a593Smuzhiyun 	char *type;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 	if (new_phy) {
210*4882a593Smuzhiyun 		if (WARN_ON_ONCE(test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)))
211*4882a593Smuzhiyun 			return;
212*4882a593Smuzhiyun 		phy->phy = sas_phy_alloc(&rphy->dev, phy_id);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 		/* FIXME: error_handling */
215*4882a593Smuzhiyun 		BUG_ON(!phy->phy);
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun 
218*4882a593Smuzhiyun 	switch (resp->result) {
219*4882a593Smuzhiyun 	case SMP_RESP_PHY_VACANT:
220*4882a593Smuzhiyun 		phy->phy_state = PHY_VACANT;
221*4882a593Smuzhiyun 		break;
222*4882a593Smuzhiyun 	default:
223*4882a593Smuzhiyun 		phy->phy_state = PHY_NOT_PRESENT;
224*4882a593Smuzhiyun 		break;
225*4882a593Smuzhiyun 	case SMP_RESP_FUNC_ACC:
226*4882a593Smuzhiyun 		phy->phy_state = PHY_EMPTY; /* do not know yet */
227*4882a593Smuzhiyun 		break;
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	/* check if anything important changed to squelch debug */
231*4882a593Smuzhiyun 	dev_type = phy->attached_dev_type;
232*4882a593Smuzhiyun 	linkrate  = phy->linkrate;
233*4882a593Smuzhiyun 	memcpy(sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	/* Handle vacant phy - rest of dr data is not valid so skip it */
236*4882a593Smuzhiyun 	if (phy->phy_state == PHY_VACANT) {
237*4882a593Smuzhiyun 		memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
238*4882a593Smuzhiyun 		phy->attached_dev_type = SAS_PHY_UNUSED;
239*4882a593Smuzhiyun 		if (!test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state)) {
240*4882a593Smuzhiyun 			phy->phy_id = phy_id;
241*4882a593Smuzhiyun 			goto skip;
242*4882a593Smuzhiyun 		} else
243*4882a593Smuzhiyun 			goto out;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	phy->attached_dev_type = to_dev_type(dr);
247*4882a593Smuzhiyun 	if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state))
248*4882a593Smuzhiyun 		goto out;
249*4882a593Smuzhiyun 	phy->phy_id = phy_id;
250*4882a593Smuzhiyun 	phy->linkrate = dr->linkrate;
251*4882a593Smuzhiyun 	phy->attached_sata_host = dr->attached_sata_host;
252*4882a593Smuzhiyun 	phy->attached_sata_dev  = dr->attached_sata_dev;
253*4882a593Smuzhiyun 	phy->attached_sata_ps   = dr->attached_sata_ps;
254*4882a593Smuzhiyun 	phy->attached_iproto = dr->iproto << 1;
255*4882a593Smuzhiyun 	phy->attached_tproto = dr->tproto << 1;
256*4882a593Smuzhiyun 	/* help some expanders that fail to zero sas_address in the 'no
257*4882a593Smuzhiyun 	 * device' case
258*4882a593Smuzhiyun 	 */
259*4882a593Smuzhiyun 	if (phy->attached_dev_type == SAS_PHY_UNUSED ||
260*4882a593Smuzhiyun 	    phy->linkrate < SAS_LINK_RATE_1_5_GBPS)
261*4882a593Smuzhiyun 		memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
262*4882a593Smuzhiyun 	else
263*4882a593Smuzhiyun 		memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE);
264*4882a593Smuzhiyun 	phy->attached_phy_id = dr->attached_phy_id;
265*4882a593Smuzhiyun 	phy->phy_change_count = dr->change_count;
266*4882a593Smuzhiyun 	phy->routing_attr = dr->routing_attr;
267*4882a593Smuzhiyun 	phy->virtual = dr->virtual;
268*4882a593Smuzhiyun 	phy->last_da_index = -1;
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	phy->phy->identify.sas_address = SAS_ADDR(phy->attached_sas_addr);
271*4882a593Smuzhiyun 	phy->phy->identify.device_type = dr->attached_dev_type;
272*4882a593Smuzhiyun 	phy->phy->identify.initiator_port_protocols = phy->attached_iproto;
273*4882a593Smuzhiyun 	phy->phy->identify.target_port_protocols = phy->attached_tproto;
274*4882a593Smuzhiyun 	if (!phy->attached_tproto && dr->attached_sata_dev)
275*4882a593Smuzhiyun 		phy->phy->identify.target_port_protocols = SAS_PROTOCOL_SATA;
276*4882a593Smuzhiyun 	phy->phy->identify.phy_identifier = phy_id;
277*4882a593Smuzhiyun 	phy->phy->minimum_linkrate_hw = dr->hmin_linkrate;
278*4882a593Smuzhiyun 	phy->phy->maximum_linkrate_hw = dr->hmax_linkrate;
279*4882a593Smuzhiyun 	phy->phy->minimum_linkrate = dr->pmin_linkrate;
280*4882a593Smuzhiyun 	phy->phy->maximum_linkrate = dr->pmax_linkrate;
281*4882a593Smuzhiyun 	phy->phy->negotiated_linkrate = phy->linkrate;
282*4882a593Smuzhiyun 	phy->phy->enabled = (phy->linkrate != SAS_PHY_DISABLED);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun  skip:
285*4882a593Smuzhiyun 	if (new_phy)
286*4882a593Smuzhiyun 		if (sas_phy_add(phy->phy)) {
287*4882a593Smuzhiyun 			sas_phy_free(phy->phy);
288*4882a593Smuzhiyun 			return;
289*4882a593Smuzhiyun 		}
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun  out:
292*4882a593Smuzhiyun 	switch (phy->attached_dev_type) {
293*4882a593Smuzhiyun 	case SAS_SATA_PENDING:
294*4882a593Smuzhiyun 		type = "stp pending";
295*4882a593Smuzhiyun 		break;
296*4882a593Smuzhiyun 	case SAS_PHY_UNUSED:
297*4882a593Smuzhiyun 		type = "no device";
298*4882a593Smuzhiyun 		break;
299*4882a593Smuzhiyun 	case SAS_END_DEVICE:
300*4882a593Smuzhiyun 		if (phy->attached_iproto) {
301*4882a593Smuzhiyun 			if (phy->attached_tproto)
302*4882a593Smuzhiyun 				type = "host+target";
303*4882a593Smuzhiyun 			else
304*4882a593Smuzhiyun 				type = "host";
305*4882a593Smuzhiyun 		} else {
306*4882a593Smuzhiyun 			if (dr->attached_sata_dev)
307*4882a593Smuzhiyun 				type = "stp";
308*4882a593Smuzhiyun 			else
309*4882a593Smuzhiyun 				type = "ssp";
310*4882a593Smuzhiyun 		}
311*4882a593Smuzhiyun 		break;
312*4882a593Smuzhiyun 	case SAS_EDGE_EXPANDER_DEVICE:
313*4882a593Smuzhiyun 	case SAS_FANOUT_EXPANDER_DEVICE:
314*4882a593Smuzhiyun 		type = "smp";
315*4882a593Smuzhiyun 		break;
316*4882a593Smuzhiyun 	default:
317*4882a593Smuzhiyun 		type = "unknown";
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	/* this routine is polled by libata error recovery so filter
321*4882a593Smuzhiyun 	 * unimportant messages
322*4882a593Smuzhiyun 	 */
323*4882a593Smuzhiyun 	if (new_phy || phy->attached_dev_type != dev_type ||
324*4882a593Smuzhiyun 	    phy->linkrate != linkrate ||
325*4882a593Smuzhiyun 	    SAS_ADDR(phy->attached_sas_addr) != SAS_ADDR(sas_addr))
326*4882a593Smuzhiyun 		/* pass */;
327*4882a593Smuzhiyun 	else
328*4882a593Smuzhiyun 		return;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	/* if the attached device type changed and ata_eh is active,
331*4882a593Smuzhiyun 	 * make sure we run revalidation when eh completes (see:
332*4882a593Smuzhiyun 	 * sas_enable_revalidation)
333*4882a593Smuzhiyun 	 */
334*4882a593Smuzhiyun 	if (test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state))
335*4882a593Smuzhiyun 		set_bit(DISCE_REVALIDATE_DOMAIN, &dev->port->disc.pending);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	pr_debug("%sex %016llx phy%02d:%c:%X attached: %016llx (%s)\n",
338*4882a593Smuzhiyun 		 test_bit(SAS_HA_ATA_EH_ACTIVE, &ha->state) ? "ata: " : "",
339*4882a593Smuzhiyun 		 SAS_ADDR(dev->sas_addr), phy->phy_id,
340*4882a593Smuzhiyun 		 sas_route_char(dev, phy), phy->linkrate,
341*4882a593Smuzhiyun 		 SAS_ADDR(phy->attached_sas_addr), type);
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun /* check if we have an existing attached ata device on this expander phy */
sas_ex_to_ata(struct domain_device * ex_dev,int phy_id)345*4882a593Smuzhiyun struct domain_device *sas_ex_to_ata(struct domain_device *ex_dev, int phy_id)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 	struct ex_phy *ex_phy = &ex_dev->ex_dev.ex_phy[phy_id];
348*4882a593Smuzhiyun 	struct domain_device *dev;
349*4882a593Smuzhiyun 	struct sas_rphy *rphy;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	if (!ex_phy->port)
352*4882a593Smuzhiyun 		return NULL;
353*4882a593Smuzhiyun 
354*4882a593Smuzhiyun 	rphy = ex_phy->port->rphy;
355*4882a593Smuzhiyun 	if (!rphy)
356*4882a593Smuzhiyun 		return NULL;
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	dev = sas_find_dev_by_rphy(rphy);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	if (dev && dev_is_sata(dev))
361*4882a593Smuzhiyun 		return dev;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	return NULL;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun #define DISCOVER_REQ_SIZE  16
367*4882a593Smuzhiyun #define DISCOVER_RESP_SIZE 56
368*4882a593Smuzhiyun 
sas_ex_phy_discover_helper(struct domain_device * dev,u8 * disc_req,u8 * disc_resp,int single)369*4882a593Smuzhiyun static int sas_ex_phy_discover_helper(struct domain_device *dev, u8 *disc_req,
370*4882a593Smuzhiyun 				      u8 *disc_resp, int single)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	struct discover_resp *dr;
373*4882a593Smuzhiyun 	int res;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	disc_req[9] = single;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
378*4882a593Smuzhiyun 			       disc_resp, DISCOVER_RESP_SIZE);
379*4882a593Smuzhiyun 	if (res)
380*4882a593Smuzhiyun 		return res;
381*4882a593Smuzhiyun 	dr = &((struct smp_resp *)disc_resp)->disc;
382*4882a593Smuzhiyun 	if (memcmp(dev->sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE) == 0) {
383*4882a593Smuzhiyun 		pr_notice("Found loopback topology, just ignore it!\n");
384*4882a593Smuzhiyun 		return 0;
385*4882a593Smuzhiyun 	}
386*4882a593Smuzhiyun 	sas_set_ex_phy(dev, single, disc_resp);
387*4882a593Smuzhiyun 	return 0;
388*4882a593Smuzhiyun }
389*4882a593Smuzhiyun 
sas_ex_phy_discover(struct domain_device * dev,int single)390*4882a593Smuzhiyun int sas_ex_phy_discover(struct domain_device *dev, int single)
391*4882a593Smuzhiyun {
392*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
393*4882a593Smuzhiyun 	int  res = 0;
394*4882a593Smuzhiyun 	u8   *disc_req;
395*4882a593Smuzhiyun 	u8   *disc_resp;
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
398*4882a593Smuzhiyun 	if (!disc_req)
399*4882a593Smuzhiyun 		return -ENOMEM;
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
402*4882a593Smuzhiyun 	if (!disc_resp) {
403*4882a593Smuzhiyun 		kfree(disc_req);
404*4882a593Smuzhiyun 		return -ENOMEM;
405*4882a593Smuzhiyun 	}
406*4882a593Smuzhiyun 
407*4882a593Smuzhiyun 	disc_req[1] = SMP_DISCOVER;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	if (0 <= single && single < ex->num_phys) {
410*4882a593Smuzhiyun 		res = sas_ex_phy_discover_helper(dev, disc_req, disc_resp, single);
411*4882a593Smuzhiyun 	} else {
412*4882a593Smuzhiyun 		int i;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 		for (i = 0; i < ex->num_phys; i++) {
415*4882a593Smuzhiyun 			res = sas_ex_phy_discover_helper(dev, disc_req,
416*4882a593Smuzhiyun 							 disc_resp, i);
417*4882a593Smuzhiyun 			if (res)
418*4882a593Smuzhiyun 				goto out_err;
419*4882a593Smuzhiyun 		}
420*4882a593Smuzhiyun 	}
421*4882a593Smuzhiyun out_err:
422*4882a593Smuzhiyun 	kfree(disc_resp);
423*4882a593Smuzhiyun 	kfree(disc_req);
424*4882a593Smuzhiyun 	return res;
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun 
sas_expander_discover(struct domain_device * dev)427*4882a593Smuzhiyun static int sas_expander_discover(struct domain_device *dev)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
430*4882a593Smuzhiyun 	int res;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	ex->ex_phy = kcalloc(ex->num_phys, sizeof(*ex->ex_phy), GFP_KERNEL);
433*4882a593Smuzhiyun 	if (!ex->ex_phy)
434*4882a593Smuzhiyun 		return -ENOMEM;
435*4882a593Smuzhiyun 
436*4882a593Smuzhiyun 	res = sas_ex_phy_discover(dev, -1);
437*4882a593Smuzhiyun 	if (res)
438*4882a593Smuzhiyun 		goto out_err;
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	return 0;
441*4882a593Smuzhiyun  out_err:
442*4882a593Smuzhiyun 	kfree(ex->ex_phy);
443*4882a593Smuzhiyun 	ex->ex_phy = NULL;
444*4882a593Smuzhiyun 	return res;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun #define MAX_EXPANDER_PHYS 128
448*4882a593Smuzhiyun 
ex_assign_report_general(struct domain_device * dev,struct smp_resp * resp)449*4882a593Smuzhiyun static void ex_assign_report_general(struct domain_device *dev,
450*4882a593Smuzhiyun 					    struct smp_resp *resp)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	struct report_general_resp *rg = &resp->rg;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count);
455*4882a593Smuzhiyun 	dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes);
456*4882a593Smuzhiyun 	dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS);
457*4882a593Smuzhiyun 	dev->ex_dev.t2t_supp = rg->t2t_supp;
458*4882a593Smuzhiyun 	dev->ex_dev.conf_route_table = rg->conf_route_table;
459*4882a593Smuzhiyun 	dev->ex_dev.configuring = rg->configuring;
460*4882a593Smuzhiyun 	memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8);
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun #define RG_REQ_SIZE   8
464*4882a593Smuzhiyun #define RG_RESP_SIZE 32
465*4882a593Smuzhiyun 
sas_ex_general(struct domain_device * dev)466*4882a593Smuzhiyun static int sas_ex_general(struct domain_device *dev)
467*4882a593Smuzhiyun {
468*4882a593Smuzhiyun 	u8 *rg_req;
469*4882a593Smuzhiyun 	struct smp_resp *rg_resp;
470*4882a593Smuzhiyun 	int res;
471*4882a593Smuzhiyun 	int i;
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	rg_req = alloc_smp_req(RG_REQ_SIZE);
474*4882a593Smuzhiyun 	if (!rg_req)
475*4882a593Smuzhiyun 		return -ENOMEM;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	rg_resp = alloc_smp_resp(RG_RESP_SIZE);
478*4882a593Smuzhiyun 	if (!rg_resp) {
479*4882a593Smuzhiyun 		kfree(rg_req);
480*4882a593Smuzhiyun 		return -ENOMEM;
481*4882a593Smuzhiyun 	}
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	rg_req[1] = SMP_REPORT_GENERAL;
484*4882a593Smuzhiyun 
485*4882a593Smuzhiyun 	for (i = 0; i < 5; i++) {
486*4882a593Smuzhiyun 		res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
487*4882a593Smuzhiyun 				       RG_RESP_SIZE);
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 		if (res) {
490*4882a593Smuzhiyun 			pr_notice("RG to ex %016llx failed:0x%x\n",
491*4882a593Smuzhiyun 				  SAS_ADDR(dev->sas_addr), res);
492*4882a593Smuzhiyun 			goto out;
493*4882a593Smuzhiyun 		} else if (rg_resp->result != SMP_RESP_FUNC_ACC) {
494*4882a593Smuzhiyun 			pr_debug("RG:ex %016llx returned SMP result:0x%x\n",
495*4882a593Smuzhiyun 				 SAS_ADDR(dev->sas_addr), rg_resp->result);
496*4882a593Smuzhiyun 			res = rg_resp->result;
497*4882a593Smuzhiyun 			goto out;
498*4882a593Smuzhiyun 		}
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 		ex_assign_report_general(dev, rg_resp);
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 		if (dev->ex_dev.configuring) {
503*4882a593Smuzhiyun 			pr_debug("RG: ex %016llx self-configuring...\n",
504*4882a593Smuzhiyun 				 SAS_ADDR(dev->sas_addr));
505*4882a593Smuzhiyun 			schedule_timeout_interruptible(5*HZ);
506*4882a593Smuzhiyun 		} else
507*4882a593Smuzhiyun 			break;
508*4882a593Smuzhiyun 	}
509*4882a593Smuzhiyun out:
510*4882a593Smuzhiyun 	kfree(rg_req);
511*4882a593Smuzhiyun 	kfree(rg_resp);
512*4882a593Smuzhiyun 	return res;
513*4882a593Smuzhiyun }
514*4882a593Smuzhiyun 
ex_assign_manuf_info(struct domain_device * dev,void * _mi_resp)515*4882a593Smuzhiyun static void ex_assign_manuf_info(struct domain_device *dev, void
516*4882a593Smuzhiyun 					*_mi_resp)
517*4882a593Smuzhiyun {
518*4882a593Smuzhiyun 	u8 *mi_resp = _mi_resp;
519*4882a593Smuzhiyun 	struct sas_rphy *rphy = dev->rphy;
520*4882a593Smuzhiyun 	struct sas_expander_device *edev = rphy_to_expander_device(rphy);
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	memcpy(edev->vendor_id, mi_resp + 12, SAS_EXPANDER_VENDOR_ID_LEN);
523*4882a593Smuzhiyun 	memcpy(edev->product_id, mi_resp + 20, SAS_EXPANDER_PRODUCT_ID_LEN);
524*4882a593Smuzhiyun 	memcpy(edev->product_rev, mi_resp + 36,
525*4882a593Smuzhiyun 	       SAS_EXPANDER_PRODUCT_REV_LEN);
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	if (mi_resp[8] & 1) {
528*4882a593Smuzhiyun 		memcpy(edev->component_vendor_id, mi_resp + 40,
529*4882a593Smuzhiyun 		       SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
530*4882a593Smuzhiyun 		edev->component_id = mi_resp[48] << 8 | mi_resp[49];
531*4882a593Smuzhiyun 		edev->component_revision_id = mi_resp[50];
532*4882a593Smuzhiyun 	}
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun #define MI_REQ_SIZE   8
536*4882a593Smuzhiyun #define MI_RESP_SIZE 64
537*4882a593Smuzhiyun 
sas_ex_manuf_info(struct domain_device * dev)538*4882a593Smuzhiyun static int sas_ex_manuf_info(struct domain_device *dev)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	u8 *mi_req;
541*4882a593Smuzhiyun 	u8 *mi_resp;
542*4882a593Smuzhiyun 	int res;
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	mi_req = alloc_smp_req(MI_REQ_SIZE);
545*4882a593Smuzhiyun 	if (!mi_req)
546*4882a593Smuzhiyun 		return -ENOMEM;
547*4882a593Smuzhiyun 
548*4882a593Smuzhiyun 	mi_resp = alloc_smp_resp(MI_RESP_SIZE);
549*4882a593Smuzhiyun 	if (!mi_resp) {
550*4882a593Smuzhiyun 		kfree(mi_req);
551*4882a593Smuzhiyun 		return -ENOMEM;
552*4882a593Smuzhiyun 	}
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	mi_req[1] = SMP_REPORT_MANUF_INFO;
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun 	res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE);
557*4882a593Smuzhiyun 	if (res) {
558*4882a593Smuzhiyun 		pr_notice("MI: ex %016llx failed:0x%x\n",
559*4882a593Smuzhiyun 			  SAS_ADDR(dev->sas_addr), res);
560*4882a593Smuzhiyun 		goto out;
561*4882a593Smuzhiyun 	} else if (mi_resp[2] != SMP_RESP_FUNC_ACC) {
562*4882a593Smuzhiyun 		pr_debug("MI ex %016llx returned SMP result:0x%x\n",
563*4882a593Smuzhiyun 			 SAS_ADDR(dev->sas_addr), mi_resp[2]);
564*4882a593Smuzhiyun 		goto out;
565*4882a593Smuzhiyun 	}
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	ex_assign_manuf_info(dev, mi_resp);
568*4882a593Smuzhiyun out:
569*4882a593Smuzhiyun 	kfree(mi_req);
570*4882a593Smuzhiyun 	kfree(mi_resp);
571*4882a593Smuzhiyun 	return res;
572*4882a593Smuzhiyun }
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun #define PC_REQ_SIZE  44
575*4882a593Smuzhiyun #define PC_RESP_SIZE 8
576*4882a593Smuzhiyun 
sas_smp_phy_control(struct domain_device * dev,int phy_id,enum phy_func phy_func,struct sas_phy_linkrates * rates)577*4882a593Smuzhiyun int sas_smp_phy_control(struct domain_device *dev, int phy_id,
578*4882a593Smuzhiyun 			enum phy_func phy_func,
579*4882a593Smuzhiyun 			struct sas_phy_linkrates *rates)
580*4882a593Smuzhiyun {
581*4882a593Smuzhiyun 	u8 *pc_req;
582*4882a593Smuzhiyun 	u8 *pc_resp;
583*4882a593Smuzhiyun 	int res;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	pc_req = alloc_smp_req(PC_REQ_SIZE);
586*4882a593Smuzhiyun 	if (!pc_req)
587*4882a593Smuzhiyun 		return -ENOMEM;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	pc_resp = alloc_smp_resp(PC_RESP_SIZE);
590*4882a593Smuzhiyun 	if (!pc_resp) {
591*4882a593Smuzhiyun 		kfree(pc_req);
592*4882a593Smuzhiyun 		return -ENOMEM;
593*4882a593Smuzhiyun 	}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	pc_req[1] = SMP_PHY_CONTROL;
596*4882a593Smuzhiyun 	pc_req[9] = phy_id;
597*4882a593Smuzhiyun 	pc_req[10]= phy_func;
598*4882a593Smuzhiyun 	if (rates) {
599*4882a593Smuzhiyun 		pc_req[32] = rates->minimum_linkrate << 4;
600*4882a593Smuzhiyun 		pc_req[33] = rates->maximum_linkrate << 4;
601*4882a593Smuzhiyun 	}
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE);
604*4882a593Smuzhiyun 	if (res) {
605*4882a593Smuzhiyun 		pr_err("ex %016llx phy%02d PHY control failed: %d\n",
606*4882a593Smuzhiyun 		       SAS_ADDR(dev->sas_addr), phy_id, res);
607*4882a593Smuzhiyun 	} else if (pc_resp[2] != SMP_RESP_FUNC_ACC) {
608*4882a593Smuzhiyun 		pr_err("ex %016llx phy%02d PHY control failed: function result 0x%x\n",
609*4882a593Smuzhiyun 		       SAS_ADDR(dev->sas_addr), phy_id, pc_resp[2]);
610*4882a593Smuzhiyun 		res = pc_resp[2];
611*4882a593Smuzhiyun 	}
612*4882a593Smuzhiyun 	kfree(pc_resp);
613*4882a593Smuzhiyun 	kfree(pc_req);
614*4882a593Smuzhiyun 	return res;
615*4882a593Smuzhiyun }
616*4882a593Smuzhiyun 
sas_ex_disable_phy(struct domain_device * dev,int phy_id)617*4882a593Smuzhiyun static void sas_ex_disable_phy(struct domain_device *dev, int phy_id)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
620*4882a593Smuzhiyun 	struct ex_phy *phy = &ex->ex_phy[phy_id];
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE, NULL);
623*4882a593Smuzhiyun 	phy->linkrate = SAS_PHY_DISABLED;
624*4882a593Smuzhiyun }
625*4882a593Smuzhiyun 
sas_ex_disable_port(struct domain_device * dev,u8 * sas_addr)626*4882a593Smuzhiyun static void sas_ex_disable_port(struct domain_device *dev, u8 *sas_addr)
627*4882a593Smuzhiyun {
628*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
629*4882a593Smuzhiyun 	int i;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	for (i = 0; i < ex->num_phys; i++) {
632*4882a593Smuzhiyun 		struct ex_phy *phy = &ex->ex_phy[i];
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 		if (phy->phy_state == PHY_VACANT ||
635*4882a593Smuzhiyun 		    phy->phy_state == PHY_NOT_PRESENT)
636*4882a593Smuzhiyun 			continue;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 		if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(sas_addr))
639*4882a593Smuzhiyun 			sas_ex_disable_phy(dev, i);
640*4882a593Smuzhiyun 	}
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun 
sas_dev_present_in_domain(struct asd_sas_port * port,u8 * sas_addr)643*4882a593Smuzhiyun static int sas_dev_present_in_domain(struct asd_sas_port *port,
644*4882a593Smuzhiyun 					    u8 *sas_addr)
645*4882a593Smuzhiyun {
646*4882a593Smuzhiyun 	struct domain_device *dev;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	if (SAS_ADDR(port->sas_addr) == SAS_ADDR(sas_addr))
649*4882a593Smuzhiyun 		return 1;
650*4882a593Smuzhiyun 	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
651*4882a593Smuzhiyun 		if (SAS_ADDR(dev->sas_addr) == SAS_ADDR(sas_addr))
652*4882a593Smuzhiyun 			return 1;
653*4882a593Smuzhiyun 	}
654*4882a593Smuzhiyun 	return 0;
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun #define RPEL_REQ_SIZE	16
658*4882a593Smuzhiyun #define RPEL_RESP_SIZE	32
sas_smp_get_phy_events(struct sas_phy * phy)659*4882a593Smuzhiyun int sas_smp_get_phy_events(struct sas_phy *phy)
660*4882a593Smuzhiyun {
661*4882a593Smuzhiyun 	int res;
662*4882a593Smuzhiyun 	u8 *req;
663*4882a593Smuzhiyun 	u8 *resp;
664*4882a593Smuzhiyun 	struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent);
665*4882a593Smuzhiyun 	struct domain_device *dev = sas_find_dev_by_rphy(rphy);
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	req = alloc_smp_req(RPEL_REQ_SIZE);
668*4882a593Smuzhiyun 	if (!req)
669*4882a593Smuzhiyun 		return -ENOMEM;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	resp = alloc_smp_resp(RPEL_RESP_SIZE);
672*4882a593Smuzhiyun 	if (!resp) {
673*4882a593Smuzhiyun 		kfree(req);
674*4882a593Smuzhiyun 		return -ENOMEM;
675*4882a593Smuzhiyun 	}
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	req[1] = SMP_REPORT_PHY_ERR_LOG;
678*4882a593Smuzhiyun 	req[9] = phy->number;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	res = smp_execute_task(dev, req, RPEL_REQ_SIZE,
681*4882a593Smuzhiyun 			            resp, RPEL_RESP_SIZE);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	if (res)
684*4882a593Smuzhiyun 		goto out;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	phy->invalid_dword_count = get_unaligned_be32(&resp[12]);
687*4882a593Smuzhiyun 	phy->running_disparity_error_count = get_unaligned_be32(&resp[16]);
688*4882a593Smuzhiyun 	phy->loss_of_dword_sync_count = get_unaligned_be32(&resp[20]);
689*4882a593Smuzhiyun 	phy->phy_reset_problem_count = get_unaligned_be32(&resp[24]);
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun  out:
692*4882a593Smuzhiyun 	kfree(req);
693*4882a593Smuzhiyun 	kfree(resp);
694*4882a593Smuzhiyun 	return res;
695*4882a593Smuzhiyun 
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun #ifdef CONFIG_SCSI_SAS_ATA
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun #define RPS_REQ_SIZE  16
701*4882a593Smuzhiyun #define RPS_RESP_SIZE 60
702*4882a593Smuzhiyun 
sas_get_report_phy_sata(struct domain_device * dev,int phy_id,struct smp_resp * rps_resp)703*4882a593Smuzhiyun int sas_get_report_phy_sata(struct domain_device *dev, int phy_id,
704*4882a593Smuzhiyun 			    struct smp_resp *rps_resp)
705*4882a593Smuzhiyun {
706*4882a593Smuzhiyun 	int res;
707*4882a593Smuzhiyun 	u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE);
708*4882a593Smuzhiyun 	u8 *resp = (u8 *)rps_resp;
709*4882a593Smuzhiyun 
710*4882a593Smuzhiyun 	if (!rps_req)
711*4882a593Smuzhiyun 		return -ENOMEM;
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	rps_req[1] = SMP_REPORT_PHY_SATA;
714*4882a593Smuzhiyun 	rps_req[9] = phy_id;
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE,
717*4882a593Smuzhiyun 			            rps_resp, RPS_RESP_SIZE);
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	/* 0x34 is the FIS type for the D2H fis.  There's a potential
720*4882a593Smuzhiyun 	 * standards cockup here.  sas-2 explicitly specifies the FIS
721*4882a593Smuzhiyun 	 * should be encoded so that FIS type is in resp[24].
722*4882a593Smuzhiyun 	 * However, some expanders endian reverse this.  Undo the
723*4882a593Smuzhiyun 	 * reversal here */
724*4882a593Smuzhiyun 	if (!res && resp[27] == 0x34 && resp[24] != 0x34) {
725*4882a593Smuzhiyun 		int i;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 		for (i = 0; i < 5; i++) {
728*4882a593Smuzhiyun 			int j = 24 + (i*4);
729*4882a593Smuzhiyun 			u8 a, b;
730*4882a593Smuzhiyun 			a = resp[j + 0];
731*4882a593Smuzhiyun 			b = resp[j + 1];
732*4882a593Smuzhiyun 			resp[j + 0] = resp[j + 3];
733*4882a593Smuzhiyun 			resp[j + 1] = resp[j + 2];
734*4882a593Smuzhiyun 			resp[j + 2] = b;
735*4882a593Smuzhiyun 			resp[j + 3] = a;
736*4882a593Smuzhiyun 		}
737*4882a593Smuzhiyun 	}
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	kfree(rps_req);
740*4882a593Smuzhiyun 	return res;
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun #endif
743*4882a593Smuzhiyun 
sas_ex_get_linkrate(struct domain_device * parent,struct domain_device * child,struct ex_phy * parent_phy)744*4882a593Smuzhiyun static void sas_ex_get_linkrate(struct domain_device *parent,
745*4882a593Smuzhiyun 				       struct domain_device *child,
746*4882a593Smuzhiyun 				       struct ex_phy *parent_phy)
747*4882a593Smuzhiyun {
748*4882a593Smuzhiyun 	struct expander_device *parent_ex = &parent->ex_dev;
749*4882a593Smuzhiyun 	struct sas_port *port;
750*4882a593Smuzhiyun 	int i;
751*4882a593Smuzhiyun 
752*4882a593Smuzhiyun 	child->pathways = 0;
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 	port = parent_phy->port;
755*4882a593Smuzhiyun 
756*4882a593Smuzhiyun 	for (i = 0; i < parent_ex->num_phys; i++) {
757*4882a593Smuzhiyun 		struct ex_phy *phy = &parent_ex->ex_phy[i];
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 		if (phy->phy_state == PHY_VACANT ||
760*4882a593Smuzhiyun 		    phy->phy_state == PHY_NOT_PRESENT)
761*4882a593Smuzhiyun 			continue;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 		if (SAS_ADDR(phy->attached_sas_addr) ==
764*4882a593Smuzhiyun 		    SAS_ADDR(child->sas_addr)) {
765*4882a593Smuzhiyun 
766*4882a593Smuzhiyun 			child->min_linkrate = min(parent->min_linkrate,
767*4882a593Smuzhiyun 						  phy->linkrate);
768*4882a593Smuzhiyun 			child->max_linkrate = max(parent->max_linkrate,
769*4882a593Smuzhiyun 						  phy->linkrate);
770*4882a593Smuzhiyun 			child->pathways++;
771*4882a593Smuzhiyun 			sas_port_add_phy(port, phy->phy);
772*4882a593Smuzhiyun 		}
773*4882a593Smuzhiyun 	}
774*4882a593Smuzhiyun 	child->linkrate = min(parent_phy->linkrate, child->max_linkrate);
775*4882a593Smuzhiyun 	child->pathways = min(child->pathways, parent->pathways);
776*4882a593Smuzhiyun }
777*4882a593Smuzhiyun 
sas_ex_discover_end_dev(struct domain_device * parent,int phy_id)778*4882a593Smuzhiyun static struct domain_device *sas_ex_discover_end_dev(
779*4882a593Smuzhiyun 	struct domain_device *parent, int phy_id)
780*4882a593Smuzhiyun {
781*4882a593Smuzhiyun 	struct expander_device *parent_ex = &parent->ex_dev;
782*4882a593Smuzhiyun 	struct ex_phy *phy = &parent_ex->ex_phy[phy_id];
783*4882a593Smuzhiyun 	struct domain_device *child = NULL;
784*4882a593Smuzhiyun 	struct sas_rphy *rphy;
785*4882a593Smuzhiyun 	int res;
786*4882a593Smuzhiyun 
787*4882a593Smuzhiyun 	if (phy->attached_sata_host || phy->attached_sata_ps)
788*4882a593Smuzhiyun 		return NULL;
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun 	child = sas_alloc_device();
791*4882a593Smuzhiyun 	if (!child)
792*4882a593Smuzhiyun 		return NULL;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	kref_get(&parent->kref);
795*4882a593Smuzhiyun 	child->parent = parent;
796*4882a593Smuzhiyun 	child->port   = parent->port;
797*4882a593Smuzhiyun 	child->iproto = phy->attached_iproto;
798*4882a593Smuzhiyun 	memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
799*4882a593Smuzhiyun 	sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
800*4882a593Smuzhiyun 	if (!phy->port) {
801*4882a593Smuzhiyun 		phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
802*4882a593Smuzhiyun 		if (unlikely(!phy->port))
803*4882a593Smuzhiyun 			goto out_err;
804*4882a593Smuzhiyun 		if (unlikely(sas_port_add(phy->port) != 0)) {
805*4882a593Smuzhiyun 			sas_port_free(phy->port);
806*4882a593Smuzhiyun 			goto out_err;
807*4882a593Smuzhiyun 		}
808*4882a593Smuzhiyun 	}
809*4882a593Smuzhiyun 	sas_ex_get_linkrate(parent, child, phy);
810*4882a593Smuzhiyun 	sas_device_set_phy(child, phy->port);
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun #ifdef CONFIG_SCSI_SAS_ATA
813*4882a593Smuzhiyun 	if ((phy->attached_tproto & SAS_PROTOCOL_STP) || phy->attached_sata_dev) {
814*4882a593Smuzhiyun 		if (child->linkrate > parent->min_linkrate) {
815*4882a593Smuzhiyun 			struct sas_phy *cphy = child->phy;
816*4882a593Smuzhiyun 			enum sas_linkrate min_prate = cphy->minimum_linkrate,
817*4882a593Smuzhiyun 				parent_min_lrate = parent->min_linkrate,
818*4882a593Smuzhiyun 				min_linkrate = (min_prate > parent_min_lrate) ?
819*4882a593Smuzhiyun 					       parent_min_lrate : 0;
820*4882a593Smuzhiyun 			struct sas_phy_linkrates rates = {
821*4882a593Smuzhiyun 				.maximum_linkrate = parent->min_linkrate,
822*4882a593Smuzhiyun 				.minimum_linkrate = min_linkrate,
823*4882a593Smuzhiyun 			};
824*4882a593Smuzhiyun 			int ret;
825*4882a593Smuzhiyun 
826*4882a593Smuzhiyun 			pr_notice("ex %016llx phy%02d SATA device linkrate > min pathway connection rate, attempting to lower device linkrate\n",
827*4882a593Smuzhiyun 				   SAS_ADDR(child->sas_addr), phy_id);
828*4882a593Smuzhiyun 			ret = sas_smp_phy_control(parent, phy_id,
829*4882a593Smuzhiyun 						  PHY_FUNC_LINK_RESET, &rates);
830*4882a593Smuzhiyun 			if (ret) {
831*4882a593Smuzhiyun 				pr_err("ex %016llx phy%02d SATA device could not set linkrate (%d)\n",
832*4882a593Smuzhiyun 				       SAS_ADDR(child->sas_addr), phy_id, ret);
833*4882a593Smuzhiyun 				goto out_free;
834*4882a593Smuzhiyun 			}
835*4882a593Smuzhiyun 			pr_notice("ex %016llx phy%02d SATA device set linkrate successfully\n",
836*4882a593Smuzhiyun 				  SAS_ADDR(child->sas_addr), phy_id);
837*4882a593Smuzhiyun 			child->linkrate = child->min_linkrate;
838*4882a593Smuzhiyun 		}
839*4882a593Smuzhiyun 		res = sas_get_ata_info(child, phy);
840*4882a593Smuzhiyun 		if (res)
841*4882a593Smuzhiyun 			goto out_free;
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun 		sas_init_dev(child);
844*4882a593Smuzhiyun 		res = sas_ata_init(child);
845*4882a593Smuzhiyun 		if (res)
846*4882a593Smuzhiyun 			goto out_free;
847*4882a593Smuzhiyun 		rphy = sas_end_device_alloc(phy->port);
848*4882a593Smuzhiyun 		if (!rphy)
849*4882a593Smuzhiyun 			goto out_free;
850*4882a593Smuzhiyun 		rphy->identify.phy_identifier = phy_id;
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 		child->rphy = rphy;
853*4882a593Smuzhiyun 		get_device(&rphy->dev);
854*4882a593Smuzhiyun 
855*4882a593Smuzhiyun 		list_add_tail(&child->disco_list_node, &parent->port->disco_list);
856*4882a593Smuzhiyun 
857*4882a593Smuzhiyun 		res = sas_discover_sata(child);
858*4882a593Smuzhiyun 		if (res) {
859*4882a593Smuzhiyun 			pr_notice("sas_discover_sata() for device %16llx at %016llx:%02d returned 0x%x\n",
860*4882a593Smuzhiyun 				  SAS_ADDR(child->sas_addr),
861*4882a593Smuzhiyun 				  SAS_ADDR(parent->sas_addr), phy_id, res);
862*4882a593Smuzhiyun 			goto out_list_del;
863*4882a593Smuzhiyun 		}
864*4882a593Smuzhiyun 	} else
865*4882a593Smuzhiyun #endif
866*4882a593Smuzhiyun 	  if (phy->attached_tproto & SAS_PROTOCOL_SSP) {
867*4882a593Smuzhiyun 		child->dev_type = SAS_END_DEVICE;
868*4882a593Smuzhiyun 		rphy = sas_end_device_alloc(phy->port);
869*4882a593Smuzhiyun 		/* FIXME: error handling */
870*4882a593Smuzhiyun 		if (unlikely(!rphy))
871*4882a593Smuzhiyun 			goto out_free;
872*4882a593Smuzhiyun 		child->tproto = phy->attached_tproto;
873*4882a593Smuzhiyun 		sas_init_dev(child);
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 		child->rphy = rphy;
876*4882a593Smuzhiyun 		get_device(&rphy->dev);
877*4882a593Smuzhiyun 		rphy->identify.phy_identifier = phy_id;
878*4882a593Smuzhiyun 		sas_fill_in_rphy(child, rphy);
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun 		list_add_tail(&child->disco_list_node, &parent->port->disco_list);
881*4882a593Smuzhiyun 
882*4882a593Smuzhiyun 		res = sas_discover_end_dev(child);
883*4882a593Smuzhiyun 		if (res) {
884*4882a593Smuzhiyun 			pr_notice("sas_discover_end_dev() for device %016llx at %016llx:%02d returned 0x%x\n",
885*4882a593Smuzhiyun 				  SAS_ADDR(child->sas_addr),
886*4882a593Smuzhiyun 				  SAS_ADDR(parent->sas_addr), phy_id, res);
887*4882a593Smuzhiyun 			goto out_list_del;
888*4882a593Smuzhiyun 		}
889*4882a593Smuzhiyun 	} else {
890*4882a593Smuzhiyun 		pr_notice("target proto 0x%x at %016llx:0x%x not handled\n",
891*4882a593Smuzhiyun 			  phy->attached_tproto, SAS_ADDR(parent->sas_addr),
892*4882a593Smuzhiyun 			  phy_id);
893*4882a593Smuzhiyun 		goto out_free;
894*4882a593Smuzhiyun 	}
895*4882a593Smuzhiyun 
896*4882a593Smuzhiyun 	list_add_tail(&child->siblings, &parent_ex->children);
897*4882a593Smuzhiyun 	return child;
898*4882a593Smuzhiyun 
899*4882a593Smuzhiyun  out_list_del:
900*4882a593Smuzhiyun 	sas_rphy_free(child->rphy);
901*4882a593Smuzhiyun 	list_del(&child->disco_list_node);
902*4882a593Smuzhiyun 	spin_lock_irq(&parent->port->dev_list_lock);
903*4882a593Smuzhiyun 	list_del(&child->dev_list_node);
904*4882a593Smuzhiyun 	spin_unlock_irq(&parent->port->dev_list_lock);
905*4882a593Smuzhiyun  out_free:
906*4882a593Smuzhiyun 	sas_port_delete(phy->port);
907*4882a593Smuzhiyun  out_err:
908*4882a593Smuzhiyun 	phy->port = NULL;
909*4882a593Smuzhiyun 	sas_put_device(child);
910*4882a593Smuzhiyun 	return NULL;
911*4882a593Smuzhiyun }
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun /* See if this phy is part of a wide port */
sas_ex_join_wide_port(struct domain_device * parent,int phy_id)914*4882a593Smuzhiyun static bool sas_ex_join_wide_port(struct domain_device *parent, int phy_id)
915*4882a593Smuzhiyun {
916*4882a593Smuzhiyun 	struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
917*4882a593Smuzhiyun 	int i;
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	for (i = 0; i < parent->ex_dev.num_phys; i++) {
920*4882a593Smuzhiyun 		struct ex_phy *ephy = &parent->ex_dev.ex_phy[i];
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 		if (ephy == phy)
923*4882a593Smuzhiyun 			continue;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 		if (!memcmp(phy->attached_sas_addr, ephy->attached_sas_addr,
926*4882a593Smuzhiyun 			    SAS_ADDR_SIZE) && ephy->port) {
927*4882a593Smuzhiyun 			sas_port_add_phy(ephy->port, phy->phy);
928*4882a593Smuzhiyun 			phy->port = ephy->port;
929*4882a593Smuzhiyun 			phy->phy_state = PHY_DEVICE_DISCOVERED;
930*4882a593Smuzhiyun 			return true;
931*4882a593Smuzhiyun 		}
932*4882a593Smuzhiyun 	}
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	return false;
935*4882a593Smuzhiyun }
936*4882a593Smuzhiyun 
sas_ex_discover_expander(struct domain_device * parent,int phy_id)937*4882a593Smuzhiyun static struct domain_device *sas_ex_discover_expander(
938*4882a593Smuzhiyun 	struct domain_device *parent, int phy_id)
939*4882a593Smuzhiyun {
940*4882a593Smuzhiyun 	struct sas_expander_device *parent_ex = rphy_to_expander_device(parent->rphy);
941*4882a593Smuzhiyun 	struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id];
942*4882a593Smuzhiyun 	struct domain_device *child = NULL;
943*4882a593Smuzhiyun 	struct sas_rphy *rphy;
944*4882a593Smuzhiyun 	struct sas_expander_device *edev;
945*4882a593Smuzhiyun 	struct asd_sas_port *port;
946*4882a593Smuzhiyun 	int res;
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	if (phy->routing_attr == DIRECT_ROUTING) {
949*4882a593Smuzhiyun 		pr_warn("ex %016llx:%02d:D <--> ex %016llx:0x%x is not allowed\n",
950*4882a593Smuzhiyun 			SAS_ADDR(parent->sas_addr), phy_id,
951*4882a593Smuzhiyun 			SAS_ADDR(phy->attached_sas_addr),
952*4882a593Smuzhiyun 			phy->attached_phy_id);
953*4882a593Smuzhiyun 		return NULL;
954*4882a593Smuzhiyun 	}
955*4882a593Smuzhiyun 	child = sas_alloc_device();
956*4882a593Smuzhiyun 	if (!child)
957*4882a593Smuzhiyun 		return NULL;
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	phy->port = sas_port_alloc(&parent->rphy->dev, phy_id);
960*4882a593Smuzhiyun 	/* FIXME: better error handling */
961*4882a593Smuzhiyun 	BUG_ON(sas_port_add(phy->port) != 0);
962*4882a593Smuzhiyun 
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	switch (phy->attached_dev_type) {
965*4882a593Smuzhiyun 	case SAS_EDGE_EXPANDER_DEVICE:
966*4882a593Smuzhiyun 		rphy = sas_expander_alloc(phy->port,
967*4882a593Smuzhiyun 					  SAS_EDGE_EXPANDER_DEVICE);
968*4882a593Smuzhiyun 		break;
969*4882a593Smuzhiyun 	case SAS_FANOUT_EXPANDER_DEVICE:
970*4882a593Smuzhiyun 		rphy = sas_expander_alloc(phy->port,
971*4882a593Smuzhiyun 					  SAS_FANOUT_EXPANDER_DEVICE);
972*4882a593Smuzhiyun 		break;
973*4882a593Smuzhiyun 	default:
974*4882a593Smuzhiyun 		rphy = NULL;	/* shut gcc up */
975*4882a593Smuzhiyun 		BUG();
976*4882a593Smuzhiyun 	}
977*4882a593Smuzhiyun 	port = parent->port;
978*4882a593Smuzhiyun 	child->rphy = rphy;
979*4882a593Smuzhiyun 	get_device(&rphy->dev);
980*4882a593Smuzhiyun 	edev = rphy_to_expander_device(rphy);
981*4882a593Smuzhiyun 	child->dev_type = phy->attached_dev_type;
982*4882a593Smuzhiyun 	kref_get(&parent->kref);
983*4882a593Smuzhiyun 	child->parent = parent;
984*4882a593Smuzhiyun 	child->port = port;
985*4882a593Smuzhiyun 	child->iproto = phy->attached_iproto;
986*4882a593Smuzhiyun 	child->tproto = phy->attached_tproto;
987*4882a593Smuzhiyun 	memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
988*4882a593Smuzhiyun 	sas_hash_addr(child->hashed_sas_addr, child->sas_addr);
989*4882a593Smuzhiyun 	sas_ex_get_linkrate(parent, child, phy);
990*4882a593Smuzhiyun 	edev->level = parent_ex->level + 1;
991*4882a593Smuzhiyun 	parent->port->disc.max_level = max(parent->port->disc.max_level,
992*4882a593Smuzhiyun 					   edev->level);
993*4882a593Smuzhiyun 	sas_init_dev(child);
994*4882a593Smuzhiyun 	sas_fill_in_rphy(child, rphy);
995*4882a593Smuzhiyun 	sas_rphy_add(rphy);
996*4882a593Smuzhiyun 
997*4882a593Smuzhiyun 	spin_lock_irq(&parent->port->dev_list_lock);
998*4882a593Smuzhiyun 	list_add_tail(&child->dev_list_node, &parent->port->dev_list);
999*4882a593Smuzhiyun 	spin_unlock_irq(&parent->port->dev_list_lock);
1000*4882a593Smuzhiyun 
1001*4882a593Smuzhiyun 	res = sas_discover_expander(child);
1002*4882a593Smuzhiyun 	if (res) {
1003*4882a593Smuzhiyun 		sas_rphy_delete(rphy);
1004*4882a593Smuzhiyun 		spin_lock_irq(&parent->port->dev_list_lock);
1005*4882a593Smuzhiyun 		list_del(&child->dev_list_node);
1006*4882a593Smuzhiyun 		spin_unlock_irq(&parent->port->dev_list_lock);
1007*4882a593Smuzhiyun 		sas_put_device(child);
1008*4882a593Smuzhiyun 		sas_port_delete(phy->port);
1009*4882a593Smuzhiyun 		phy->port = NULL;
1010*4882a593Smuzhiyun 		return NULL;
1011*4882a593Smuzhiyun 	}
1012*4882a593Smuzhiyun 	list_add_tail(&child->siblings, &parent->ex_dev.children);
1013*4882a593Smuzhiyun 	return child;
1014*4882a593Smuzhiyun }
1015*4882a593Smuzhiyun 
sas_ex_discover_dev(struct domain_device * dev,int phy_id)1016*4882a593Smuzhiyun static int sas_ex_discover_dev(struct domain_device *dev, int phy_id)
1017*4882a593Smuzhiyun {
1018*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1019*4882a593Smuzhiyun 	struct ex_phy *ex_phy = &ex->ex_phy[phy_id];
1020*4882a593Smuzhiyun 	struct domain_device *child = NULL;
1021*4882a593Smuzhiyun 	int res = 0;
1022*4882a593Smuzhiyun 
1023*4882a593Smuzhiyun 	/* Phy state */
1024*4882a593Smuzhiyun 	if (ex_phy->linkrate == SAS_SATA_SPINUP_HOLD) {
1025*4882a593Smuzhiyun 		if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET, NULL))
1026*4882a593Smuzhiyun 			res = sas_ex_phy_discover(dev, phy_id);
1027*4882a593Smuzhiyun 		if (res)
1028*4882a593Smuzhiyun 			return res;
1029*4882a593Smuzhiyun 	}
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	/* Parent and domain coherency */
1032*4882a593Smuzhiyun 	if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
1033*4882a593Smuzhiyun 			     SAS_ADDR(dev->port->sas_addr))) {
1034*4882a593Smuzhiyun 		sas_add_parent_port(dev, phy_id);
1035*4882a593Smuzhiyun 		return 0;
1036*4882a593Smuzhiyun 	}
1037*4882a593Smuzhiyun 	if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) ==
1038*4882a593Smuzhiyun 			    SAS_ADDR(dev->parent->sas_addr))) {
1039*4882a593Smuzhiyun 		sas_add_parent_port(dev, phy_id);
1040*4882a593Smuzhiyun 		if (ex_phy->routing_attr == TABLE_ROUTING)
1041*4882a593Smuzhiyun 			sas_configure_phy(dev, phy_id, dev->port->sas_addr, 1);
1042*4882a593Smuzhiyun 		return 0;
1043*4882a593Smuzhiyun 	}
1044*4882a593Smuzhiyun 
1045*4882a593Smuzhiyun 	if (sas_dev_present_in_domain(dev->port, ex_phy->attached_sas_addr))
1046*4882a593Smuzhiyun 		sas_ex_disable_port(dev, ex_phy->attached_sas_addr);
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	if (ex_phy->attached_dev_type == SAS_PHY_UNUSED) {
1049*4882a593Smuzhiyun 		if (ex_phy->routing_attr == DIRECT_ROUTING) {
1050*4882a593Smuzhiyun 			memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
1051*4882a593Smuzhiyun 			sas_configure_routing(dev, ex_phy->attached_sas_addr);
1052*4882a593Smuzhiyun 		}
1053*4882a593Smuzhiyun 		return 0;
1054*4882a593Smuzhiyun 	} else if (ex_phy->linkrate == SAS_LINK_RATE_UNKNOWN)
1055*4882a593Smuzhiyun 		return 0;
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun 	if (ex_phy->attached_dev_type != SAS_END_DEVICE &&
1058*4882a593Smuzhiyun 	    ex_phy->attached_dev_type != SAS_FANOUT_EXPANDER_DEVICE &&
1059*4882a593Smuzhiyun 	    ex_phy->attached_dev_type != SAS_EDGE_EXPANDER_DEVICE &&
1060*4882a593Smuzhiyun 	    ex_phy->attached_dev_type != SAS_SATA_PENDING) {
1061*4882a593Smuzhiyun 		pr_warn("unknown device type(0x%x) attached to ex %016llx phy%02d\n",
1062*4882a593Smuzhiyun 			ex_phy->attached_dev_type,
1063*4882a593Smuzhiyun 			SAS_ADDR(dev->sas_addr),
1064*4882a593Smuzhiyun 			phy_id);
1065*4882a593Smuzhiyun 		return 0;
1066*4882a593Smuzhiyun 	}
1067*4882a593Smuzhiyun 
1068*4882a593Smuzhiyun 	res = sas_configure_routing(dev, ex_phy->attached_sas_addr);
1069*4882a593Smuzhiyun 	if (res) {
1070*4882a593Smuzhiyun 		pr_notice("configure routing for dev %016llx reported 0x%x. Forgotten\n",
1071*4882a593Smuzhiyun 			  SAS_ADDR(ex_phy->attached_sas_addr), res);
1072*4882a593Smuzhiyun 		sas_disable_routing(dev, ex_phy->attached_sas_addr);
1073*4882a593Smuzhiyun 		return res;
1074*4882a593Smuzhiyun 	}
1075*4882a593Smuzhiyun 
1076*4882a593Smuzhiyun 	if (sas_ex_join_wide_port(dev, phy_id)) {
1077*4882a593Smuzhiyun 		pr_debug("Attaching ex phy%02d to wide port %016llx\n",
1078*4882a593Smuzhiyun 			 phy_id, SAS_ADDR(ex_phy->attached_sas_addr));
1079*4882a593Smuzhiyun 		return res;
1080*4882a593Smuzhiyun 	}
1081*4882a593Smuzhiyun 
1082*4882a593Smuzhiyun 	switch (ex_phy->attached_dev_type) {
1083*4882a593Smuzhiyun 	case SAS_END_DEVICE:
1084*4882a593Smuzhiyun 	case SAS_SATA_PENDING:
1085*4882a593Smuzhiyun 		child = sas_ex_discover_end_dev(dev, phy_id);
1086*4882a593Smuzhiyun 		break;
1087*4882a593Smuzhiyun 	case SAS_FANOUT_EXPANDER_DEVICE:
1088*4882a593Smuzhiyun 		if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) {
1089*4882a593Smuzhiyun 			pr_debug("second fanout expander %016llx phy%02d attached to ex %016llx phy%02d\n",
1090*4882a593Smuzhiyun 				 SAS_ADDR(ex_phy->attached_sas_addr),
1091*4882a593Smuzhiyun 				 ex_phy->attached_phy_id,
1092*4882a593Smuzhiyun 				 SAS_ADDR(dev->sas_addr),
1093*4882a593Smuzhiyun 				 phy_id);
1094*4882a593Smuzhiyun 			sas_ex_disable_phy(dev, phy_id);
1095*4882a593Smuzhiyun 			return res;
1096*4882a593Smuzhiyun 		} else
1097*4882a593Smuzhiyun 			memcpy(dev->port->disc.fanout_sas_addr,
1098*4882a593Smuzhiyun 			       ex_phy->attached_sas_addr, SAS_ADDR_SIZE);
1099*4882a593Smuzhiyun 		fallthrough;
1100*4882a593Smuzhiyun 	case SAS_EDGE_EXPANDER_DEVICE:
1101*4882a593Smuzhiyun 		child = sas_ex_discover_expander(dev, phy_id);
1102*4882a593Smuzhiyun 		break;
1103*4882a593Smuzhiyun 	default:
1104*4882a593Smuzhiyun 		break;
1105*4882a593Smuzhiyun 	}
1106*4882a593Smuzhiyun 
1107*4882a593Smuzhiyun 	if (!child)
1108*4882a593Smuzhiyun 		pr_notice("ex %016llx phy%02d failed to discover\n",
1109*4882a593Smuzhiyun 			  SAS_ADDR(dev->sas_addr), phy_id);
1110*4882a593Smuzhiyun 	return res;
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun 
sas_find_sub_addr(struct domain_device * dev,u8 * sub_addr)1113*4882a593Smuzhiyun static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr)
1114*4882a593Smuzhiyun {
1115*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1116*4882a593Smuzhiyun 	int i;
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	for (i = 0; i < ex->num_phys; i++) {
1119*4882a593Smuzhiyun 		struct ex_phy *phy = &ex->ex_phy[i];
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 		if (phy->phy_state == PHY_VACANT ||
1122*4882a593Smuzhiyun 		    phy->phy_state == PHY_NOT_PRESENT)
1123*4882a593Smuzhiyun 			continue;
1124*4882a593Smuzhiyun 
1125*4882a593Smuzhiyun 		if (dev_is_expander(phy->attached_dev_type) &&
1126*4882a593Smuzhiyun 		    phy->routing_attr == SUBTRACTIVE_ROUTING) {
1127*4882a593Smuzhiyun 
1128*4882a593Smuzhiyun 			memcpy(sub_addr, phy->attached_sas_addr, SAS_ADDR_SIZE);
1129*4882a593Smuzhiyun 
1130*4882a593Smuzhiyun 			return 1;
1131*4882a593Smuzhiyun 		}
1132*4882a593Smuzhiyun 	}
1133*4882a593Smuzhiyun 	return 0;
1134*4882a593Smuzhiyun }
1135*4882a593Smuzhiyun 
sas_check_level_subtractive_boundary(struct domain_device * dev)1136*4882a593Smuzhiyun static int sas_check_level_subtractive_boundary(struct domain_device *dev)
1137*4882a593Smuzhiyun {
1138*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1139*4882a593Smuzhiyun 	struct domain_device *child;
1140*4882a593Smuzhiyun 	u8 sub_addr[SAS_ADDR_SIZE] = {0, };
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	list_for_each_entry(child, &ex->children, siblings) {
1143*4882a593Smuzhiyun 		if (!dev_is_expander(child->dev_type))
1144*4882a593Smuzhiyun 			continue;
1145*4882a593Smuzhiyun 		if (sub_addr[0] == 0) {
1146*4882a593Smuzhiyun 			sas_find_sub_addr(child, sub_addr);
1147*4882a593Smuzhiyun 			continue;
1148*4882a593Smuzhiyun 		} else {
1149*4882a593Smuzhiyun 			u8 s2[SAS_ADDR_SIZE];
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 			if (sas_find_sub_addr(child, s2) &&
1152*4882a593Smuzhiyun 			    (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) {
1153*4882a593Smuzhiyun 
1154*4882a593Smuzhiyun 				pr_notice("ex %016llx->%016llx-?->%016llx diverges from subtractive boundary %016llx\n",
1155*4882a593Smuzhiyun 					  SAS_ADDR(dev->sas_addr),
1156*4882a593Smuzhiyun 					  SAS_ADDR(child->sas_addr),
1157*4882a593Smuzhiyun 					  SAS_ADDR(s2),
1158*4882a593Smuzhiyun 					  SAS_ADDR(sub_addr));
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 				sas_ex_disable_port(child, s2);
1161*4882a593Smuzhiyun 			}
1162*4882a593Smuzhiyun 		}
1163*4882a593Smuzhiyun 	}
1164*4882a593Smuzhiyun 	return 0;
1165*4882a593Smuzhiyun }
1166*4882a593Smuzhiyun /**
1167*4882a593Smuzhiyun  * sas_ex_discover_devices - discover devices attached to this expander
1168*4882a593Smuzhiyun  * @dev: pointer to the expander domain device
1169*4882a593Smuzhiyun  * @single: if you want to do a single phy, else set to -1;
1170*4882a593Smuzhiyun  *
1171*4882a593Smuzhiyun  * Configure this expander for use with its devices and register the
1172*4882a593Smuzhiyun  * devices of this expander.
1173*4882a593Smuzhiyun  */
sas_ex_discover_devices(struct domain_device * dev,int single)1174*4882a593Smuzhiyun static int sas_ex_discover_devices(struct domain_device *dev, int single)
1175*4882a593Smuzhiyun {
1176*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1177*4882a593Smuzhiyun 	int i = 0, end = ex->num_phys;
1178*4882a593Smuzhiyun 	int res = 0;
1179*4882a593Smuzhiyun 
1180*4882a593Smuzhiyun 	if (0 <= single && single < end) {
1181*4882a593Smuzhiyun 		i = single;
1182*4882a593Smuzhiyun 		end = i+1;
1183*4882a593Smuzhiyun 	}
1184*4882a593Smuzhiyun 
1185*4882a593Smuzhiyun 	for ( ; i < end; i++) {
1186*4882a593Smuzhiyun 		struct ex_phy *ex_phy = &ex->ex_phy[i];
1187*4882a593Smuzhiyun 
1188*4882a593Smuzhiyun 		if (ex_phy->phy_state == PHY_VACANT ||
1189*4882a593Smuzhiyun 		    ex_phy->phy_state == PHY_NOT_PRESENT ||
1190*4882a593Smuzhiyun 		    ex_phy->phy_state == PHY_DEVICE_DISCOVERED)
1191*4882a593Smuzhiyun 			continue;
1192*4882a593Smuzhiyun 
1193*4882a593Smuzhiyun 		switch (ex_phy->linkrate) {
1194*4882a593Smuzhiyun 		case SAS_PHY_DISABLED:
1195*4882a593Smuzhiyun 		case SAS_PHY_RESET_PROBLEM:
1196*4882a593Smuzhiyun 		case SAS_SATA_PORT_SELECTOR:
1197*4882a593Smuzhiyun 			continue;
1198*4882a593Smuzhiyun 		default:
1199*4882a593Smuzhiyun 			res = sas_ex_discover_dev(dev, i);
1200*4882a593Smuzhiyun 			if (res)
1201*4882a593Smuzhiyun 				break;
1202*4882a593Smuzhiyun 			continue;
1203*4882a593Smuzhiyun 		}
1204*4882a593Smuzhiyun 	}
1205*4882a593Smuzhiyun 
1206*4882a593Smuzhiyun 	if (!res)
1207*4882a593Smuzhiyun 		sas_check_level_subtractive_boundary(dev);
1208*4882a593Smuzhiyun 
1209*4882a593Smuzhiyun 	return res;
1210*4882a593Smuzhiyun }
1211*4882a593Smuzhiyun 
sas_check_ex_subtractive_boundary(struct domain_device * dev)1212*4882a593Smuzhiyun static int sas_check_ex_subtractive_boundary(struct domain_device *dev)
1213*4882a593Smuzhiyun {
1214*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1215*4882a593Smuzhiyun 	int i;
1216*4882a593Smuzhiyun 	u8  *sub_sas_addr = NULL;
1217*4882a593Smuzhiyun 
1218*4882a593Smuzhiyun 	if (dev->dev_type != SAS_EDGE_EXPANDER_DEVICE)
1219*4882a593Smuzhiyun 		return 0;
1220*4882a593Smuzhiyun 
1221*4882a593Smuzhiyun 	for (i = 0; i < ex->num_phys; i++) {
1222*4882a593Smuzhiyun 		struct ex_phy *phy = &ex->ex_phy[i];
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 		if (phy->phy_state == PHY_VACANT ||
1225*4882a593Smuzhiyun 		    phy->phy_state == PHY_NOT_PRESENT)
1226*4882a593Smuzhiyun 			continue;
1227*4882a593Smuzhiyun 
1228*4882a593Smuzhiyun 		if (dev_is_expander(phy->attached_dev_type) &&
1229*4882a593Smuzhiyun 		    phy->routing_attr == SUBTRACTIVE_ROUTING) {
1230*4882a593Smuzhiyun 
1231*4882a593Smuzhiyun 			if (!sub_sas_addr)
1232*4882a593Smuzhiyun 				sub_sas_addr = &phy->attached_sas_addr[0];
1233*4882a593Smuzhiyun 			else if (SAS_ADDR(sub_sas_addr) !=
1234*4882a593Smuzhiyun 				 SAS_ADDR(phy->attached_sas_addr)) {
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 				pr_notice("ex %016llx phy%02d diverges(%016llx) on subtractive boundary(%016llx). Disabled\n",
1237*4882a593Smuzhiyun 					  SAS_ADDR(dev->sas_addr), i,
1238*4882a593Smuzhiyun 					  SAS_ADDR(phy->attached_sas_addr),
1239*4882a593Smuzhiyun 					  SAS_ADDR(sub_sas_addr));
1240*4882a593Smuzhiyun 				sas_ex_disable_phy(dev, i);
1241*4882a593Smuzhiyun 			}
1242*4882a593Smuzhiyun 		}
1243*4882a593Smuzhiyun 	}
1244*4882a593Smuzhiyun 	return 0;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun 
sas_print_parent_topology_bug(struct domain_device * child,struct ex_phy * parent_phy,struct ex_phy * child_phy)1247*4882a593Smuzhiyun static void sas_print_parent_topology_bug(struct domain_device *child,
1248*4882a593Smuzhiyun 						 struct ex_phy *parent_phy,
1249*4882a593Smuzhiyun 						 struct ex_phy *child_phy)
1250*4882a593Smuzhiyun {
1251*4882a593Smuzhiyun 	static const char *ex_type[] = {
1252*4882a593Smuzhiyun 		[SAS_EDGE_EXPANDER_DEVICE] = "edge",
1253*4882a593Smuzhiyun 		[SAS_FANOUT_EXPANDER_DEVICE] = "fanout",
1254*4882a593Smuzhiyun 	};
1255*4882a593Smuzhiyun 	struct domain_device *parent = child->parent;
1256*4882a593Smuzhiyun 
1257*4882a593Smuzhiyun 	pr_notice("%s ex %016llx phy%02d <--> %s ex %016llx phy%02d has %c:%c routing link!\n",
1258*4882a593Smuzhiyun 		  ex_type[parent->dev_type],
1259*4882a593Smuzhiyun 		  SAS_ADDR(parent->sas_addr),
1260*4882a593Smuzhiyun 		  parent_phy->phy_id,
1261*4882a593Smuzhiyun 
1262*4882a593Smuzhiyun 		  ex_type[child->dev_type],
1263*4882a593Smuzhiyun 		  SAS_ADDR(child->sas_addr),
1264*4882a593Smuzhiyun 		  child_phy->phy_id,
1265*4882a593Smuzhiyun 
1266*4882a593Smuzhiyun 		  sas_route_char(parent, parent_phy),
1267*4882a593Smuzhiyun 		  sas_route_char(child, child_phy));
1268*4882a593Smuzhiyun }
1269*4882a593Smuzhiyun 
sas_check_eeds(struct domain_device * child,struct ex_phy * parent_phy,struct ex_phy * child_phy)1270*4882a593Smuzhiyun static int sas_check_eeds(struct domain_device *child,
1271*4882a593Smuzhiyun 				 struct ex_phy *parent_phy,
1272*4882a593Smuzhiyun 				 struct ex_phy *child_phy)
1273*4882a593Smuzhiyun {
1274*4882a593Smuzhiyun 	int res = 0;
1275*4882a593Smuzhiyun 	struct domain_device *parent = child->parent;
1276*4882a593Smuzhiyun 
1277*4882a593Smuzhiyun 	if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) {
1278*4882a593Smuzhiyun 		res = -ENODEV;
1279*4882a593Smuzhiyun 		pr_warn("edge ex %016llx phy S:%02d <--> edge ex %016llx phy S:%02d, while there is a fanout ex %016llx\n",
1280*4882a593Smuzhiyun 			SAS_ADDR(parent->sas_addr),
1281*4882a593Smuzhiyun 			parent_phy->phy_id,
1282*4882a593Smuzhiyun 			SAS_ADDR(child->sas_addr),
1283*4882a593Smuzhiyun 			child_phy->phy_id,
1284*4882a593Smuzhiyun 			SAS_ADDR(parent->port->disc.fanout_sas_addr));
1285*4882a593Smuzhiyun 	} else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) {
1286*4882a593Smuzhiyun 		memcpy(parent->port->disc.eeds_a, parent->sas_addr,
1287*4882a593Smuzhiyun 		       SAS_ADDR_SIZE);
1288*4882a593Smuzhiyun 		memcpy(parent->port->disc.eeds_b, child->sas_addr,
1289*4882a593Smuzhiyun 		       SAS_ADDR_SIZE);
1290*4882a593Smuzhiyun 	} else if (((SAS_ADDR(parent->port->disc.eeds_a) ==
1291*4882a593Smuzhiyun 		    SAS_ADDR(parent->sas_addr)) ||
1292*4882a593Smuzhiyun 		   (SAS_ADDR(parent->port->disc.eeds_a) ==
1293*4882a593Smuzhiyun 		    SAS_ADDR(child->sas_addr)))
1294*4882a593Smuzhiyun 		   &&
1295*4882a593Smuzhiyun 		   ((SAS_ADDR(parent->port->disc.eeds_b) ==
1296*4882a593Smuzhiyun 		     SAS_ADDR(parent->sas_addr)) ||
1297*4882a593Smuzhiyun 		    (SAS_ADDR(parent->port->disc.eeds_b) ==
1298*4882a593Smuzhiyun 		     SAS_ADDR(child->sas_addr))))
1299*4882a593Smuzhiyun 		;
1300*4882a593Smuzhiyun 	else {
1301*4882a593Smuzhiyun 		res = -ENODEV;
1302*4882a593Smuzhiyun 		pr_warn("edge ex %016llx phy%02d <--> edge ex %016llx phy%02d link forms a third EEDS!\n",
1303*4882a593Smuzhiyun 			SAS_ADDR(parent->sas_addr),
1304*4882a593Smuzhiyun 			parent_phy->phy_id,
1305*4882a593Smuzhiyun 			SAS_ADDR(child->sas_addr),
1306*4882a593Smuzhiyun 			child_phy->phy_id);
1307*4882a593Smuzhiyun 	}
1308*4882a593Smuzhiyun 
1309*4882a593Smuzhiyun 	return res;
1310*4882a593Smuzhiyun }
1311*4882a593Smuzhiyun 
1312*4882a593Smuzhiyun /* Here we spill over 80 columns.  It is intentional.
1313*4882a593Smuzhiyun  */
sas_check_parent_topology(struct domain_device * child)1314*4882a593Smuzhiyun static int sas_check_parent_topology(struct domain_device *child)
1315*4882a593Smuzhiyun {
1316*4882a593Smuzhiyun 	struct expander_device *child_ex = &child->ex_dev;
1317*4882a593Smuzhiyun 	struct expander_device *parent_ex;
1318*4882a593Smuzhiyun 	int i;
1319*4882a593Smuzhiyun 	int res = 0;
1320*4882a593Smuzhiyun 
1321*4882a593Smuzhiyun 	if (!child->parent)
1322*4882a593Smuzhiyun 		return 0;
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun 	if (!dev_is_expander(child->parent->dev_type))
1325*4882a593Smuzhiyun 		return 0;
1326*4882a593Smuzhiyun 
1327*4882a593Smuzhiyun 	parent_ex = &child->parent->ex_dev;
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun 	for (i = 0; i < parent_ex->num_phys; i++) {
1330*4882a593Smuzhiyun 		struct ex_phy *parent_phy = &parent_ex->ex_phy[i];
1331*4882a593Smuzhiyun 		struct ex_phy *child_phy;
1332*4882a593Smuzhiyun 
1333*4882a593Smuzhiyun 		if (parent_phy->phy_state == PHY_VACANT ||
1334*4882a593Smuzhiyun 		    parent_phy->phy_state == PHY_NOT_PRESENT)
1335*4882a593Smuzhiyun 			continue;
1336*4882a593Smuzhiyun 
1337*4882a593Smuzhiyun 		if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr))
1338*4882a593Smuzhiyun 			continue;
1339*4882a593Smuzhiyun 
1340*4882a593Smuzhiyun 		child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id];
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun 		switch (child->parent->dev_type) {
1343*4882a593Smuzhiyun 		case SAS_EDGE_EXPANDER_DEVICE:
1344*4882a593Smuzhiyun 			if (child->dev_type == SAS_FANOUT_EXPANDER_DEVICE) {
1345*4882a593Smuzhiyun 				if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING ||
1346*4882a593Smuzhiyun 				    child_phy->routing_attr != TABLE_ROUTING) {
1347*4882a593Smuzhiyun 					sas_print_parent_topology_bug(child, parent_phy, child_phy);
1348*4882a593Smuzhiyun 					res = -ENODEV;
1349*4882a593Smuzhiyun 				}
1350*4882a593Smuzhiyun 			} else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) {
1351*4882a593Smuzhiyun 				if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) {
1352*4882a593Smuzhiyun 					res = sas_check_eeds(child, parent_phy, child_phy);
1353*4882a593Smuzhiyun 				} else if (child_phy->routing_attr != TABLE_ROUTING) {
1354*4882a593Smuzhiyun 					sas_print_parent_topology_bug(child, parent_phy, child_phy);
1355*4882a593Smuzhiyun 					res = -ENODEV;
1356*4882a593Smuzhiyun 				}
1357*4882a593Smuzhiyun 			} else if (parent_phy->routing_attr == TABLE_ROUTING) {
1358*4882a593Smuzhiyun 				if (child_phy->routing_attr == SUBTRACTIVE_ROUTING ||
1359*4882a593Smuzhiyun 				    (child_phy->routing_attr == TABLE_ROUTING &&
1360*4882a593Smuzhiyun 				     child_ex->t2t_supp && parent_ex->t2t_supp)) {
1361*4882a593Smuzhiyun 					/* All good */;
1362*4882a593Smuzhiyun 				} else {
1363*4882a593Smuzhiyun 					sas_print_parent_topology_bug(child, parent_phy, child_phy);
1364*4882a593Smuzhiyun 					res = -ENODEV;
1365*4882a593Smuzhiyun 				}
1366*4882a593Smuzhiyun 			}
1367*4882a593Smuzhiyun 			break;
1368*4882a593Smuzhiyun 		case SAS_FANOUT_EXPANDER_DEVICE:
1369*4882a593Smuzhiyun 			if (parent_phy->routing_attr != TABLE_ROUTING ||
1370*4882a593Smuzhiyun 			    child_phy->routing_attr != SUBTRACTIVE_ROUTING) {
1371*4882a593Smuzhiyun 				sas_print_parent_topology_bug(child, parent_phy, child_phy);
1372*4882a593Smuzhiyun 				res = -ENODEV;
1373*4882a593Smuzhiyun 			}
1374*4882a593Smuzhiyun 			break;
1375*4882a593Smuzhiyun 		default:
1376*4882a593Smuzhiyun 			break;
1377*4882a593Smuzhiyun 		}
1378*4882a593Smuzhiyun 	}
1379*4882a593Smuzhiyun 
1380*4882a593Smuzhiyun 	return res;
1381*4882a593Smuzhiyun }
1382*4882a593Smuzhiyun 
1383*4882a593Smuzhiyun #define RRI_REQ_SIZE  16
1384*4882a593Smuzhiyun #define RRI_RESP_SIZE 44
1385*4882a593Smuzhiyun 
sas_configure_present(struct domain_device * dev,int phy_id,u8 * sas_addr,int * index,int * present)1386*4882a593Smuzhiyun static int sas_configure_present(struct domain_device *dev, int phy_id,
1387*4882a593Smuzhiyun 				 u8 *sas_addr, int *index, int *present)
1388*4882a593Smuzhiyun {
1389*4882a593Smuzhiyun 	int i, res = 0;
1390*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1391*4882a593Smuzhiyun 	struct ex_phy *phy = &ex->ex_phy[phy_id];
1392*4882a593Smuzhiyun 	u8 *rri_req;
1393*4882a593Smuzhiyun 	u8 *rri_resp;
1394*4882a593Smuzhiyun 
1395*4882a593Smuzhiyun 	*present = 0;
1396*4882a593Smuzhiyun 	*index = 0;
1397*4882a593Smuzhiyun 
1398*4882a593Smuzhiyun 	rri_req = alloc_smp_req(RRI_REQ_SIZE);
1399*4882a593Smuzhiyun 	if (!rri_req)
1400*4882a593Smuzhiyun 		return -ENOMEM;
1401*4882a593Smuzhiyun 
1402*4882a593Smuzhiyun 	rri_resp = alloc_smp_resp(RRI_RESP_SIZE);
1403*4882a593Smuzhiyun 	if (!rri_resp) {
1404*4882a593Smuzhiyun 		kfree(rri_req);
1405*4882a593Smuzhiyun 		return -ENOMEM;
1406*4882a593Smuzhiyun 	}
1407*4882a593Smuzhiyun 
1408*4882a593Smuzhiyun 	rri_req[1] = SMP_REPORT_ROUTE_INFO;
1409*4882a593Smuzhiyun 	rri_req[9] = phy_id;
1410*4882a593Smuzhiyun 
1411*4882a593Smuzhiyun 	for (i = 0; i < ex->max_route_indexes ; i++) {
1412*4882a593Smuzhiyun 		*(__be16 *)(rri_req+6) = cpu_to_be16(i);
1413*4882a593Smuzhiyun 		res = smp_execute_task(dev, rri_req, RRI_REQ_SIZE, rri_resp,
1414*4882a593Smuzhiyun 				       RRI_RESP_SIZE);
1415*4882a593Smuzhiyun 		if (res)
1416*4882a593Smuzhiyun 			goto out;
1417*4882a593Smuzhiyun 		res = rri_resp[2];
1418*4882a593Smuzhiyun 		if (res == SMP_RESP_NO_INDEX) {
1419*4882a593Smuzhiyun 			pr_warn("overflow of indexes: dev %016llx phy%02d index 0x%x\n",
1420*4882a593Smuzhiyun 				SAS_ADDR(dev->sas_addr), phy_id, i);
1421*4882a593Smuzhiyun 			goto out;
1422*4882a593Smuzhiyun 		} else if (res != SMP_RESP_FUNC_ACC) {
1423*4882a593Smuzhiyun 			pr_notice("%s: dev %016llx phy%02d index 0x%x result 0x%x\n",
1424*4882a593Smuzhiyun 				  __func__, SAS_ADDR(dev->sas_addr), phy_id,
1425*4882a593Smuzhiyun 				  i, res);
1426*4882a593Smuzhiyun 			goto out;
1427*4882a593Smuzhiyun 		}
1428*4882a593Smuzhiyun 		if (SAS_ADDR(sas_addr) != 0) {
1429*4882a593Smuzhiyun 			if (SAS_ADDR(rri_resp+16) == SAS_ADDR(sas_addr)) {
1430*4882a593Smuzhiyun 				*index = i;
1431*4882a593Smuzhiyun 				if ((rri_resp[12] & 0x80) == 0x80)
1432*4882a593Smuzhiyun 					*present = 0;
1433*4882a593Smuzhiyun 				else
1434*4882a593Smuzhiyun 					*present = 1;
1435*4882a593Smuzhiyun 				goto out;
1436*4882a593Smuzhiyun 			} else if (SAS_ADDR(rri_resp+16) == 0) {
1437*4882a593Smuzhiyun 				*index = i;
1438*4882a593Smuzhiyun 				*present = 0;
1439*4882a593Smuzhiyun 				goto out;
1440*4882a593Smuzhiyun 			}
1441*4882a593Smuzhiyun 		} else if (SAS_ADDR(rri_resp+16) == 0 &&
1442*4882a593Smuzhiyun 			   phy->last_da_index < i) {
1443*4882a593Smuzhiyun 			phy->last_da_index = i;
1444*4882a593Smuzhiyun 			*index = i;
1445*4882a593Smuzhiyun 			*present = 0;
1446*4882a593Smuzhiyun 			goto out;
1447*4882a593Smuzhiyun 		}
1448*4882a593Smuzhiyun 	}
1449*4882a593Smuzhiyun 	res = -1;
1450*4882a593Smuzhiyun out:
1451*4882a593Smuzhiyun 	kfree(rri_req);
1452*4882a593Smuzhiyun 	kfree(rri_resp);
1453*4882a593Smuzhiyun 	return res;
1454*4882a593Smuzhiyun }
1455*4882a593Smuzhiyun 
1456*4882a593Smuzhiyun #define CRI_REQ_SIZE  44
1457*4882a593Smuzhiyun #define CRI_RESP_SIZE  8
1458*4882a593Smuzhiyun 
sas_configure_set(struct domain_device * dev,int phy_id,u8 * sas_addr,int index,int include)1459*4882a593Smuzhiyun static int sas_configure_set(struct domain_device *dev, int phy_id,
1460*4882a593Smuzhiyun 			     u8 *sas_addr, int index, int include)
1461*4882a593Smuzhiyun {
1462*4882a593Smuzhiyun 	int res;
1463*4882a593Smuzhiyun 	u8 *cri_req;
1464*4882a593Smuzhiyun 	u8 *cri_resp;
1465*4882a593Smuzhiyun 
1466*4882a593Smuzhiyun 	cri_req = alloc_smp_req(CRI_REQ_SIZE);
1467*4882a593Smuzhiyun 	if (!cri_req)
1468*4882a593Smuzhiyun 		return -ENOMEM;
1469*4882a593Smuzhiyun 
1470*4882a593Smuzhiyun 	cri_resp = alloc_smp_resp(CRI_RESP_SIZE);
1471*4882a593Smuzhiyun 	if (!cri_resp) {
1472*4882a593Smuzhiyun 		kfree(cri_req);
1473*4882a593Smuzhiyun 		return -ENOMEM;
1474*4882a593Smuzhiyun 	}
1475*4882a593Smuzhiyun 
1476*4882a593Smuzhiyun 	cri_req[1] = SMP_CONF_ROUTE_INFO;
1477*4882a593Smuzhiyun 	*(__be16 *)(cri_req+6) = cpu_to_be16(index);
1478*4882a593Smuzhiyun 	cri_req[9] = phy_id;
1479*4882a593Smuzhiyun 	if (SAS_ADDR(sas_addr) == 0 || !include)
1480*4882a593Smuzhiyun 		cri_req[12] |= 0x80;
1481*4882a593Smuzhiyun 	memcpy(cri_req+16, sas_addr, SAS_ADDR_SIZE);
1482*4882a593Smuzhiyun 
1483*4882a593Smuzhiyun 	res = smp_execute_task(dev, cri_req, CRI_REQ_SIZE, cri_resp,
1484*4882a593Smuzhiyun 			       CRI_RESP_SIZE);
1485*4882a593Smuzhiyun 	if (res)
1486*4882a593Smuzhiyun 		goto out;
1487*4882a593Smuzhiyun 	res = cri_resp[2];
1488*4882a593Smuzhiyun 	if (res == SMP_RESP_NO_INDEX) {
1489*4882a593Smuzhiyun 		pr_warn("overflow of indexes: dev %016llx phy%02d index 0x%x\n",
1490*4882a593Smuzhiyun 			SAS_ADDR(dev->sas_addr), phy_id, index);
1491*4882a593Smuzhiyun 	}
1492*4882a593Smuzhiyun out:
1493*4882a593Smuzhiyun 	kfree(cri_req);
1494*4882a593Smuzhiyun 	kfree(cri_resp);
1495*4882a593Smuzhiyun 	return res;
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun 
sas_configure_phy(struct domain_device * dev,int phy_id,u8 * sas_addr,int include)1498*4882a593Smuzhiyun static int sas_configure_phy(struct domain_device *dev, int phy_id,
1499*4882a593Smuzhiyun 				    u8 *sas_addr, int include)
1500*4882a593Smuzhiyun {
1501*4882a593Smuzhiyun 	int index;
1502*4882a593Smuzhiyun 	int present;
1503*4882a593Smuzhiyun 	int res;
1504*4882a593Smuzhiyun 
1505*4882a593Smuzhiyun 	res = sas_configure_present(dev, phy_id, sas_addr, &index, &present);
1506*4882a593Smuzhiyun 	if (res)
1507*4882a593Smuzhiyun 		return res;
1508*4882a593Smuzhiyun 	if (include ^ present)
1509*4882a593Smuzhiyun 		return sas_configure_set(dev, phy_id, sas_addr, index,include);
1510*4882a593Smuzhiyun 
1511*4882a593Smuzhiyun 	return res;
1512*4882a593Smuzhiyun }
1513*4882a593Smuzhiyun 
1514*4882a593Smuzhiyun /**
1515*4882a593Smuzhiyun  * sas_configure_parent - configure routing table of parent
1516*4882a593Smuzhiyun  * @parent: parent expander
1517*4882a593Smuzhiyun  * @child: child expander
1518*4882a593Smuzhiyun  * @sas_addr: SAS port identifier of device directly attached to child
1519*4882a593Smuzhiyun  * @include: whether or not to include @child in the expander routing table
1520*4882a593Smuzhiyun  */
sas_configure_parent(struct domain_device * parent,struct domain_device * child,u8 * sas_addr,int include)1521*4882a593Smuzhiyun static int sas_configure_parent(struct domain_device *parent,
1522*4882a593Smuzhiyun 				struct domain_device *child,
1523*4882a593Smuzhiyun 				u8 *sas_addr, int include)
1524*4882a593Smuzhiyun {
1525*4882a593Smuzhiyun 	struct expander_device *ex_parent = &parent->ex_dev;
1526*4882a593Smuzhiyun 	int res = 0;
1527*4882a593Smuzhiyun 	int i;
1528*4882a593Smuzhiyun 
1529*4882a593Smuzhiyun 	if (parent->parent) {
1530*4882a593Smuzhiyun 		res = sas_configure_parent(parent->parent, parent, sas_addr,
1531*4882a593Smuzhiyun 					   include);
1532*4882a593Smuzhiyun 		if (res)
1533*4882a593Smuzhiyun 			return res;
1534*4882a593Smuzhiyun 	}
1535*4882a593Smuzhiyun 
1536*4882a593Smuzhiyun 	if (ex_parent->conf_route_table == 0) {
1537*4882a593Smuzhiyun 		pr_debug("ex %016llx has self-configuring routing table\n",
1538*4882a593Smuzhiyun 			 SAS_ADDR(parent->sas_addr));
1539*4882a593Smuzhiyun 		return 0;
1540*4882a593Smuzhiyun 	}
1541*4882a593Smuzhiyun 
1542*4882a593Smuzhiyun 	for (i = 0; i < ex_parent->num_phys; i++) {
1543*4882a593Smuzhiyun 		struct ex_phy *phy = &ex_parent->ex_phy[i];
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 		if ((phy->routing_attr == TABLE_ROUTING) &&
1546*4882a593Smuzhiyun 		    (SAS_ADDR(phy->attached_sas_addr) ==
1547*4882a593Smuzhiyun 		     SAS_ADDR(child->sas_addr))) {
1548*4882a593Smuzhiyun 			res = sas_configure_phy(parent, i, sas_addr, include);
1549*4882a593Smuzhiyun 			if (res)
1550*4882a593Smuzhiyun 				return res;
1551*4882a593Smuzhiyun 		}
1552*4882a593Smuzhiyun 	}
1553*4882a593Smuzhiyun 
1554*4882a593Smuzhiyun 	return res;
1555*4882a593Smuzhiyun }
1556*4882a593Smuzhiyun 
1557*4882a593Smuzhiyun /**
1558*4882a593Smuzhiyun  * sas_configure_routing - configure routing
1559*4882a593Smuzhiyun  * @dev: expander device
1560*4882a593Smuzhiyun  * @sas_addr: port identifier of device directly attached to the expander device
1561*4882a593Smuzhiyun  */
sas_configure_routing(struct domain_device * dev,u8 * sas_addr)1562*4882a593Smuzhiyun static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr)
1563*4882a593Smuzhiyun {
1564*4882a593Smuzhiyun 	if (dev->parent)
1565*4882a593Smuzhiyun 		return sas_configure_parent(dev->parent, dev, sas_addr, 1);
1566*4882a593Smuzhiyun 	return 0;
1567*4882a593Smuzhiyun }
1568*4882a593Smuzhiyun 
sas_disable_routing(struct domain_device * dev,u8 * sas_addr)1569*4882a593Smuzhiyun static int sas_disable_routing(struct domain_device *dev,  u8 *sas_addr)
1570*4882a593Smuzhiyun {
1571*4882a593Smuzhiyun 	if (dev->parent)
1572*4882a593Smuzhiyun 		return sas_configure_parent(dev->parent, dev, sas_addr, 0);
1573*4882a593Smuzhiyun 	return 0;
1574*4882a593Smuzhiyun }
1575*4882a593Smuzhiyun 
1576*4882a593Smuzhiyun /**
1577*4882a593Smuzhiyun  * sas_discover_expander - expander discovery
1578*4882a593Smuzhiyun  * @dev: pointer to expander domain device
1579*4882a593Smuzhiyun  *
1580*4882a593Smuzhiyun  * See comment in sas_discover_sata().
1581*4882a593Smuzhiyun  */
sas_discover_expander(struct domain_device * dev)1582*4882a593Smuzhiyun static int sas_discover_expander(struct domain_device *dev)
1583*4882a593Smuzhiyun {
1584*4882a593Smuzhiyun 	int res;
1585*4882a593Smuzhiyun 
1586*4882a593Smuzhiyun 	res = sas_notify_lldd_dev_found(dev);
1587*4882a593Smuzhiyun 	if (res)
1588*4882a593Smuzhiyun 		return res;
1589*4882a593Smuzhiyun 
1590*4882a593Smuzhiyun 	res = sas_ex_general(dev);
1591*4882a593Smuzhiyun 	if (res)
1592*4882a593Smuzhiyun 		goto out_err;
1593*4882a593Smuzhiyun 	res = sas_ex_manuf_info(dev);
1594*4882a593Smuzhiyun 	if (res)
1595*4882a593Smuzhiyun 		goto out_err;
1596*4882a593Smuzhiyun 
1597*4882a593Smuzhiyun 	res = sas_expander_discover(dev);
1598*4882a593Smuzhiyun 	if (res) {
1599*4882a593Smuzhiyun 		pr_warn("expander %016llx discovery failed(0x%x)\n",
1600*4882a593Smuzhiyun 			SAS_ADDR(dev->sas_addr), res);
1601*4882a593Smuzhiyun 		goto out_err;
1602*4882a593Smuzhiyun 	}
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun 	sas_check_ex_subtractive_boundary(dev);
1605*4882a593Smuzhiyun 	res = sas_check_parent_topology(dev);
1606*4882a593Smuzhiyun 	if (res)
1607*4882a593Smuzhiyun 		goto out_err;
1608*4882a593Smuzhiyun 	return 0;
1609*4882a593Smuzhiyun out_err:
1610*4882a593Smuzhiyun 	sas_notify_lldd_dev_gone(dev);
1611*4882a593Smuzhiyun 	return res;
1612*4882a593Smuzhiyun }
1613*4882a593Smuzhiyun 
sas_ex_level_discovery(struct asd_sas_port * port,const int level)1614*4882a593Smuzhiyun static int sas_ex_level_discovery(struct asd_sas_port *port, const int level)
1615*4882a593Smuzhiyun {
1616*4882a593Smuzhiyun 	int res = 0;
1617*4882a593Smuzhiyun 	struct domain_device *dev;
1618*4882a593Smuzhiyun 
1619*4882a593Smuzhiyun 	list_for_each_entry(dev, &port->dev_list, dev_list_node) {
1620*4882a593Smuzhiyun 		if (dev_is_expander(dev->dev_type)) {
1621*4882a593Smuzhiyun 			struct sas_expander_device *ex =
1622*4882a593Smuzhiyun 				rphy_to_expander_device(dev->rphy);
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 			if (level == ex->level)
1625*4882a593Smuzhiyun 				res = sas_ex_discover_devices(dev, -1);
1626*4882a593Smuzhiyun 			else if (level > 0)
1627*4882a593Smuzhiyun 				res = sas_ex_discover_devices(port->port_dev, -1);
1628*4882a593Smuzhiyun 
1629*4882a593Smuzhiyun 		}
1630*4882a593Smuzhiyun 	}
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun 	return res;
1633*4882a593Smuzhiyun }
1634*4882a593Smuzhiyun 
sas_ex_bfs_disc(struct asd_sas_port * port)1635*4882a593Smuzhiyun static int sas_ex_bfs_disc(struct asd_sas_port *port)
1636*4882a593Smuzhiyun {
1637*4882a593Smuzhiyun 	int res;
1638*4882a593Smuzhiyun 	int level;
1639*4882a593Smuzhiyun 
1640*4882a593Smuzhiyun 	do {
1641*4882a593Smuzhiyun 		level = port->disc.max_level;
1642*4882a593Smuzhiyun 		res = sas_ex_level_discovery(port, level);
1643*4882a593Smuzhiyun 		mb();
1644*4882a593Smuzhiyun 	} while (level < port->disc.max_level);
1645*4882a593Smuzhiyun 
1646*4882a593Smuzhiyun 	return res;
1647*4882a593Smuzhiyun }
1648*4882a593Smuzhiyun 
sas_discover_root_expander(struct domain_device * dev)1649*4882a593Smuzhiyun int sas_discover_root_expander(struct domain_device *dev)
1650*4882a593Smuzhiyun {
1651*4882a593Smuzhiyun 	int res;
1652*4882a593Smuzhiyun 	struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
1653*4882a593Smuzhiyun 
1654*4882a593Smuzhiyun 	res = sas_rphy_add(dev->rphy);
1655*4882a593Smuzhiyun 	if (res)
1656*4882a593Smuzhiyun 		goto out_err;
1657*4882a593Smuzhiyun 
1658*4882a593Smuzhiyun 	ex->level = dev->port->disc.max_level; /* 0 */
1659*4882a593Smuzhiyun 	res = sas_discover_expander(dev);
1660*4882a593Smuzhiyun 	if (res)
1661*4882a593Smuzhiyun 		goto out_err2;
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 	sas_ex_bfs_disc(dev->port);
1664*4882a593Smuzhiyun 
1665*4882a593Smuzhiyun 	return res;
1666*4882a593Smuzhiyun 
1667*4882a593Smuzhiyun out_err2:
1668*4882a593Smuzhiyun 	sas_rphy_remove(dev->rphy);
1669*4882a593Smuzhiyun out_err:
1670*4882a593Smuzhiyun 	return res;
1671*4882a593Smuzhiyun }
1672*4882a593Smuzhiyun 
1673*4882a593Smuzhiyun /* ---------- Domain revalidation ---------- */
1674*4882a593Smuzhiyun 
sas_get_phy_discover(struct domain_device * dev,int phy_id,struct smp_resp * disc_resp)1675*4882a593Smuzhiyun static int sas_get_phy_discover(struct domain_device *dev,
1676*4882a593Smuzhiyun 				int phy_id, struct smp_resp *disc_resp)
1677*4882a593Smuzhiyun {
1678*4882a593Smuzhiyun 	int res;
1679*4882a593Smuzhiyun 	u8 *disc_req;
1680*4882a593Smuzhiyun 
1681*4882a593Smuzhiyun 	disc_req = alloc_smp_req(DISCOVER_REQ_SIZE);
1682*4882a593Smuzhiyun 	if (!disc_req)
1683*4882a593Smuzhiyun 		return -ENOMEM;
1684*4882a593Smuzhiyun 
1685*4882a593Smuzhiyun 	disc_req[1] = SMP_DISCOVER;
1686*4882a593Smuzhiyun 	disc_req[9] = phy_id;
1687*4882a593Smuzhiyun 
1688*4882a593Smuzhiyun 	res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE,
1689*4882a593Smuzhiyun 			       disc_resp, DISCOVER_RESP_SIZE);
1690*4882a593Smuzhiyun 	if (res)
1691*4882a593Smuzhiyun 		goto out;
1692*4882a593Smuzhiyun 	else if (disc_resp->result != SMP_RESP_FUNC_ACC) {
1693*4882a593Smuzhiyun 		res = disc_resp->result;
1694*4882a593Smuzhiyun 		goto out;
1695*4882a593Smuzhiyun 	}
1696*4882a593Smuzhiyun out:
1697*4882a593Smuzhiyun 	kfree(disc_req);
1698*4882a593Smuzhiyun 	return res;
1699*4882a593Smuzhiyun }
1700*4882a593Smuzhiyun 
sas_get_phy_change_count(struct domain_device * dev,int phy_id,int * pcc)1701*4882a593Smuzhiyun static int sas_get_phy_change_count(struct domain_device *dev,
1702*4882a593Smuzhiyun 				    int phy_id, int *pcc)
1703*4882a593Smuzhiyun {
1704*4882a593Smuzhiyun 	int res;
1705*4882a593Smuzhiyun 	struct smp_resp *disc_resp;
1706*4882a593Smuzhiyun 
1707*4882a593Smuzhiyun 	disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
1708*4882a593Smuzhiyun 	if (!disc_resp)
1709*4882a593Smuzhiyun 		return -ENOMEM;
1710*4882a593Smuzhiyun 
1711*4882a593Smuzhiyun 	res = sas_get_phy_discover(dev, phy_id, disc_resp);
1712*4882a593Smuzhiyun 	if (!res)
1713*4882a593Smuzhiyun 		*pcc = disc_resp->disc.change_count;
1714*4882a593Smuzhiyun 
1715*4882a593Smuzhiyun 	kfree(disc_resp);
1716*4882a593Smuzhiyun 	return res;
1717*4882a593Smuzhiyun }
1718*4882a593Smuzhiyun 
sas_get_phy_attached_dev(struct domain_device * dev,int phy_id,u8 * sas_addr,enum sas_device_type * type)1719*4882a593Smuzhiyun static int sas_get_phy_attached_dev(struct domain_device *dev, int phy_id,
1720*4882a593Smuzhiyun 				    u8 *sas_addr, enum sas_device_type *type)
1721*4882a593Smuzhiyun {
1722*4882a593Smuzhiyun 	int res;
1723*4882a593Smuzhiyun 	struct smp_resp *disc_resp;
1724*4882a593Smuzhiyun 	struct discover_resp *dr;
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 	disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE);
1727*4882a593Smuzhiyun 	if (!disc_resp)
1728*4882a593Smuzhiyun 		return -ENOMEM;
1729*4882a593Smuzhiyun 	dr = &disc_resp->disc;
1730*4882a593Smuzhiyun 
1731*4882a593Smuzhiyun 	res = sas_get_phy_discover(dev, phy_id, disc_resp);
1732*4882a593Smuzhiyun 	if (res == 0) {
1733*4882a593Smuzhiyun 		memcpy(sas_addr, disc_resp->disc.attached_sas_addr,
1734*4882a593Smuzhiyun 		       SAS_ADDR_SIZE);
1735*4882a593Smuzhiyun 		*type = to_dev_type(dr);
1736*4882a593Smuzhiyun 		if (*type == 0)
1737*4882a593Smuzhiyun 			memset(sas_addr, 0, SAS_ADDR_SIZE);
1738*4882a593Smuzhiyun 	}
1739*4882a593Smuzhiyun 	kfree(disc_resp);
1740*4882a593Smuzhiyun 	return res;
1741*4882a593Smuzhiyun }
1742*4882a593Smuzhiyun 
sas_find_bcast_phy(struct domain_device * dev,int * phy_id,int from_phy,bool update)1743*4882a593Smuzhiyun static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id,
1744*4882a593Smuzhiyun 			      int from_phy, bool update)
1745*4882a593Smuzhiyun {
1746*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1747*4882a593Smuzhiyun 	int res = 0;
1748*4882a593Smuzhiyun 	int i;
1749*4882a593Smuzhiyun 
1750*4882a593Smuzhiyun 	for (i = from_phy; i < ex->num_phys; i++) {
1751*4882a593Smuzhiyun 		int phy_change_count = 0;
1752*4882a593Smuzhiyun 
1753*4882a593Smuzhiyun 		res = sas_get_phy_change_count(dev, i, &phy_change_count);
1754*4882a593Smuzhiyun 		switch (res) {
1755*4882a593Smuzhiyun 		case SMP_RESP_PHY_VACANT:
1756*4882a593Smuzhiyun 		case SMP_RESP_NO_PHY:
1757*4882a593Smuzhiyun 			continue;
1758*4882a593Smuzhiyun 		case SMP_RESP_FUNC_ACC:
1759*4882a593Smuzhiyun 			break;
1760*4882a593Smuzhiyun 		default:
1761*4882a593Smuzhiyun 			return res;
1762*4882a593Smuzhiyun 		}
1763*4882a593Smuzhiyun 
1764*4882a593Smuzhiyun 		if (phy_change_count != ex->ex_phy[i].phy_change_count) {
1765*4882a593Smuzhiyun 			if (update)
1766*4882a593Smuzhiyun 				ex->ex_phy[i].phy_change_count =
1767*4882a593Smuzhiyun 					phy_change_count;
1768*4882a593Smuzhiyun 			*phy_id = i;
1769*4882a593Smuzhiyun 			return 0;
1770*4882a593Smuzhiyun 		}
1771*4882a593Smuzhiyun 	}
1772*4882a593Smuzhiyun 	return 0;
1773*4882a593Smuzhiyun }
1774*4882a593Smuzhiyun 
sas_get_ex_change_count(struct domain_device * dev,int * ecc)1775*4882a593Smuzhiyun static int sas_get_ex_change_count(struct domain_device *dev, int *ecc)
1776*4882a593Smuzhiyun {
1777*4882a593Smuzhiyun 	int res;
1778*4882a593Smuzhiyun 	u8  *rg_req;
1779*4882a593Smuzhiyun 	struct smp_resp  *rg_resp;
1780*4882a593Smuzhiyun 
1781*4882a593Smuzhiyun 	rg_req = alloc_smp_req(RG_REQ_SIZE);
1782*4882a593Smuzhiyun 	if (!rg_req)
1783*4882a593Smuzhiyun 		return -ENOMEM;
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun 	rg_resp = alloc_smp_resp(RG_RESP_SIZE);
1786*4882a593Smuzhiyun 	if (!rg_resp) {
1787*4882a593Smuzhiyun 		kfree(rg_req);
1788*4882a593Smuzhiyun 		return -ENOMEM;
1789*4882a593Smuzhiyun 	}
1790*4882a593Smuzhiyun 
1791*4882a593Smuzhiyun 	rg_req[1] = SMP_REPORT_GENERAL;
1792*4882a593Smuzhiyun 
1793*4882a593Smuzhiyun 	res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp,
1794*4882a593Smuzhiyun 			       RG_RESP_SIZE);
1795*4882a593Smuzhiyun 	if (res)
1796*4882a593Smuzhiyun 		goto out;
1797*4882a593Smuzhiyun 	if (rg_resp->result != SMP_RESP_FUNC_ACC) {
1798*4882a593Smuzhiyun 		res = rg_resp->result;
1799*4882a593Smuzhiyun 		goto out;
1800*4882a593Smuzhiyun 	}
1801*4882a593Smuzhiyun 
1802*4882a593Smuzhiyun 	*ecc = be16_to_cpu(rg_resp->rg.change_count);
1803*4882a593Smuzhiyun out:
1804*4882a593Smuzhiyun 	kfree(rg_resp);
1805*4882a593Smuzhiyun 	kfree(rg_req);
1806*4882a593Smuzhiyun 	return res;
1807*4882a593Smuzhiyun }
1808*4882a593Smuzhiyun /**
1809*4882a593Smuzhiyun  * sas_find_bcast_dev -  find the device issue BROADCAST(CHANGE).
1810*4882a593Smuzhiyun  * @dev:domain device to be detect.
1811*4882a593Smuzhiyun  * @src_dev: the device which originated BROADCAST(CHANGE).
1812*4882a593Smuzhiyun  *
1813*4882a593Smuzhiyun  * Add self-configuration expander support. Suppose two expander cascading,
1814*4882a593Smuzhiyun  * when the first level expander is self-configuring, hotplug the disks in
1815*4882a593Smuzhiyun  * second level expander, BROADCAST(CHANGE) will not only be originated
1816*4882a593Smuzhiyun  * in the second level expander, but also be originated in the first level
1817*4882a593Smuzhiyun  * expander (see SAS protocol SAS 2r-14, 7.11 for detail), it is to say,
1818*4882a593Smuzhiyun  * expander changed count in two level expanders will all increment at least
1819*4882a593Smuzhiyun  * once, but the phy which chang count has changed is the source device which
1820*4882a593Smuzhiyun  * we concerned.
1821*4882a593Smuzhiyun  */
1822*4882a593Smuzhiyun 
sas_find_bcast_dev(struct domain_device * dev,struct domain_device ** src_dev)1823*4882a593Smuzhiyun static int sas_find_bcast_dev(struct domain_device *dev,
1824*4882a593Smuzhiyun 			      struct domain_device **src_dev)
1825*4882a593Smuzhiyun {
1826*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1827*4882a593Smuzhiyun 	int ex_change_count = -1;
1828*4882a593Smuzhiyun 	int phy_id = -1;
1829*4882a593Smuzhiyun 	int res;
1830*4882a593Smuzhiyun 	struct domain_device *ch;
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun 	res = sas_get_ex_change_count(dev, &ex_change_count);
1833*4882a593Smuzhiyun 	if (res)
1834*4882a593Smuzhiyun 		goto out;
1835*4882a593Smuzhiyun 	if (ex_change_count != -1 && ex_change_count != ex->ex_change_count) {
1836*4882a593Smuzhiyun 		/* Just detect if this expander phys phy change count changed,
1837*4882a593Smuzhiyun 		* in order to determine if this expander originate BROADCAST,
1838*4882a593Smuzhiyun 		* and do not update phy change count field in our structure.
1839*4882a593Smuzhiyun 		*/
1840*4882a593Smuzhiyun 		res = sas_find_bcast_phy(dev, &phy_id, 0, false);
1841*4882a593Smuzhiyun 		if (phy_id != -1) {
1842*4882a593Smuzhiyun 			*src_dev = dev;
1843*4882a593Smuzhiyun 			ex->ex_change_count = ex_change_count;
1844*4882a593Smuzhiyun 			pr_info("ex %016llx phy%02d change count has changed\n",
1845*4882a593Smuzhiyun 				SAS_ADDR(dev->sas_addr), phy_id);
1846*4882a593Smuzhiyun 			return res;
1847*4882a593Smuzhiyun 		} else
1848*4882a593Smuzhiyun 			pr_info("ex %016llx phys DID NOT change\n",
1849*4882a593Smuzhiyun 				SAS_ADDR(dev->sas_addr));
1850*4882a593Smuzhiyun 	}
1851*4882a593Smuzhiyun 	list_for_each_entry(ch, &ex->children, siblings) {
1852*4882a593Smuzhiyun 		if (dev_is_expander(ch->dev_type)) {
1853*4882a593Smuzhiyun 			res = sas_find_bcast_dev(ch, src_dev);
1854*4882a593Smuzhiyun 			if (*src_dev)
1855*4882a593Smuzhiyun 				return res;
1856*4882a593Smuzhiyun 		}
1857*4882a593Smuzhiyun 	}
1858*4882a593Smuzhiyun out:
1859*4882a593Smuzhiyun 	return res;
1860*4882a593Smuzhiyun }
1861*4882a593Smuzhiyun 
sas_unregister_ex_tree(struct asd_sas_port * port,struct domain_device * dev)1862*4882a593Smuzhiyun static void sas_unregister_ex_tree(struct asd_sas_port *port, struct domain_device *dev)
1863*4882a593Smuzhiyun {
1864*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1865*4882a593Smuzhiyun 	struct domain_device *child, *n;
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	list_for_each_entry_safe(child, n, &ex->children, siblings) {
1868*4882a593Smuzhiyun 		set_bit(SAS_DEV_GONE, &child->state);
1869*4882a593Smuzhiyun 		if (dev_is_expander(child->dev_type))
1870*4882a593Smuzhiyun 			sas_unregister_ex_tree(port, child);
1871*4882a593Smuzhiyun 		else
1872*4882a593Smuzhiyun 			sas_unregister_dev(port, child);
1873*4882a593Smuzhiyun 	}
1874*4882a593Smuzhiyun 	sas_unregister_dev(port, dev);
1875*4882a593Smuzhiyun }
1876*4882a593Smuzhiyun 
sas_unregister_devs_sas_addr(struct domain_device * parent,int phy_id,bool last)1877*4882a593Smuzhiyun static void sas_unregister_devs_sas_addr(struct domain_device *parent,
1878*4882a593Smuzhiyun 					 int phy_id, bool last)
1879*4882a593Smuzhiyun {
1880*4882a593Smuzhiyun 	struct expander_device *ex_dev = &parent->ex_dev;
1881*4882a593Smuzhiyun 	struct ex_phy *phy = &ex_dev->ex_phy[phy_id];
1882*4882a593Smuzhiyun 	struct domain_device *child, *n, *found = NULL;
1883*4882a593Smuzhiyun 	if (last) {
1884*4882a593Smuzhiyun 		list_for_each_entry_safe(child, n,
1885*4882a593Smuzhiyun 			&ex_dev->children, siblings) {
1886*4882a593Smuzhiyun 			if (SAS_ADDR(child->sas_addr) ==
1887*4882a593Smuzhiyun 			    SAS_ADDR(phy->attached_sas_addr)) {
1888*4882a593Smuzhiyun 				set_bit(SAS_DEV_GONE, &child->state);
1889*4882a593Smuzhiyun 				if (dev_is_expander(child->dev_type))
1890*4882a593Smuzhiyun 					sas_unregister_ex_tree(parent->port, child);
1891*4882a593Smuzhiyun 				else
1892*4882a593Smuzhiyun 					sas_unregister_dev(parent->port, child);
1893*4882a593Smuzhiyun 				found = child;
1894*4882a593Smuzhiyun 				break;
1895*4882a593Smuzhiyun 			}
1896*4882a593Smuzhiyun 		}
1897*4882a593Smuzhiyun 		sas_disable_routing(parent, phy->attached_sas_addr);
1898*4882a593Smuzhiyun 	}
1899*4882a593Smuzhiyun 	memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE);
1900*4882a593Smuzhiyun 	if (phy->port) {
1901*4882a593Smuzhiyun 		sas_port_delete_phy(phy->port, phy->phy);
1902*4882a593Smuzhiyun 		sas_device_set_phy(found, phy->port);
1903*4882a593Smuzhiyun 		if (phy->port->num_phys == 0)
1904*4882a593Smuzhiyun 			list_add_tail(&phy->port->del_list,
1905*4882a593Smuzhiyun 				&parent->port->sas_port_del_list);
1906*4882a593Smuzhiyun 		phy->port = NULL;
1907*4882a593Smuzhiyun 	}
1908*4882a593Smuzhiyun }
1909*4882a593Smuzhiyun 
sas_discover_bfs_by_root_level(struct domain_device * root,const int level)1910*4882a593Smuzhiyun static int sas_discover_bfs_by_root_level(struct domain_device *root,
1911*4882a593Smuzhiyun 					  const int level)
1912*4882a593Smuzhiyun {
1913*4882a593Smuzhiyun 	struct expander_device *ex_root = &root->ex_dev;
1914*4882a593Smuzhiyun 	struct domain_device *child;
1915*4882a593Smuzhiyun 	int res = 0;
1916*4882a593Smuzhiyun 
1917*4882a593Smuzhiyun 	list_for_each_entry(child, &ex_root->children, siblings) {
1918*4882a593Smuzhiyun 		if (dev_is_expander(child->dev_type)) {
1919*4882a593Smuzhiyun 			struct sas_expander_device *ex =
1920*4882a593Smuzhiyun 				rphy_to_expander_device(child->rphy);
1921*4882a593Smuzhiyun 
1922*4882a593Smuzhiyun 			if (level > ex->level)
1923*4882a593Smuzhiyun 				res = sas_discover_bfs_by_root_level(child,
1924*4882a593Smuzhiyun 								     level);
1925*4882a593Smuzhiyun 			else if (level == ex->level)
1926*4882a593Smuzhiyun 				res = sas_ex_discover_devices(child, -1);
1927*4882a593Smuzhiyun 		}
1928*4882a593Smuzhiyun 	}
1929*4882a593Smuzhiyun 	return res;
1930*4882a593Smuzhiyun }
1931*4882a593Smuzhiyun 
sas_discover_bfs_by_root(struct domain_device * dev)1932*4882a593Smuzhiyun static int sas_discover_bfs_by_root(struct domain_device *dev)
1933*4882a593Smuzhiyun {
1934*4882a593Smuzhiyun 	int res;
1935*4882a593Smuzhiyun 	struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy);
1936*4882a593Smuzhiyun 	int level = ex->level+1;
1937*4882a593Smuzhiyun 
1938*4882a593Smuzhiyun 	res = sas_ex_discover_devices(dev, -1);
1939*4882a593Smuzhiyun 	if (res)
1940*4882a593Smuzhiyun 		goto out;
1941*4882a593Smuzhiyun 	do {
1942*4882a593Smuzhiyun 		res = sas_discover_bfs_by_root_level(dev, level);
1943*4882a593Smuzhiyun 		mb();
1944*4882a593Smuzhiyun 		level += 1;
1945*4882a593Smuzhiyun 	} while (level <= dev->port->disc.max_level);
1946*4882a593Smuzhiyun out:
1947*4882a593Smuzhiyun 	return res;
1948*4882a593Smuzhiyun }
1949*4882a593Smuzhiyun 
sas_discover_new(struct domain_device * dev,int phy_id)1950*4882a593Smuzhiyun static int sas_discover_new(struct domain_device *dev, int phy_id)
1951*4882a593Smuzhiyun {
1952*4882a593Smuzhiyun 	struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id];
1953*4882a593Smuzhiyun 	struct domain_device *child;
1954*4882a593Smuzhiyun 	int res;
1955*4882a593Smuzhiyun 
1956*4882a593Smuzhiyun 	pr_debug("ex %016llx phy%02d new device attached\n",
1957*4882a593Smuzhiyun 		 SAS_ADDR(dev->sas_addr), phy_id);
1958*4882a593Smuzhiyun 	res = sas_ex_phy_discover(dev, phy_id);
1959*4882a593Smuzhiyun 	if (res)
1960*4882a593Smuzhiyun 		return res;
1961*4882a593Smuzhiyun 
1962*4882a593Smuzhiyun 	if (sas_ex_join_wide_port(dev, phy_id))
1963*4882a593Smuzhiyun 		return 0;
1964*4882a593Smuzhiyun 
1965*4882a593Smuzhiyun 	res = sas_ex_discover_devices(dev, phy_id);
1966*4882a593Smuzhiyun 	if (res)
1967*4882a593Smuzhiyun 		return res;
1968*4882a593Smuzhiyun 	list_for_each_entry(child, &dev->ex_dev.children, siblings) {
1969*4882a593Smuzhiyun 		if (SAS_ADDR(child->sas_addr) ==
1970*4882a593Smuzhiyun 		    SAS_ADDR(ex_phy->attached_sas_addr)) {
1971*4882a593Smuzhiyun 			if (dev_is_expander(child->dev_type))
1972*4882a593Smuzhiyun 				res = sas_discover_bfs_by_root(child);
1973*4882a593Smuzhiyun 			break;
1974*4882a593Smuzhiyun 		}
1975*4882a593Smuzhiyun 	}
1976*4882a593Smuzhiyun 	return res;
1977*4882a593Smuzhiyun }
1978*4882a593Smuzhiyun 
dev_type_flutter(enum sas_device_type new,enum sas_device_type old)1979*4882a593Smuzhiyun static bool dev_type_flutter(enum sas_device_type new, enum sas_device_type old)
1980*4882a593Smuzhiyun {
1981*4882a593Smuzhiyun 	if (old == new)
1982*4882a593Smuzhiyun 		return true;
1983*4882a593Smuzhiyun 
1984*4882a593Smuzhiyun 	/* treat device directed resets as flutter, if we went
1985*4882a593Smuzhiyun 	 * SAS_END_DEVICE to SAS_SATA_PENDING the link needs recovery
1986*4882a593Smuzhiyun 	 */
1987*4882a593Smuzhiyun 	if ((old == SAS_SATA_PENDING && new == SAS_END_DEVICE) ||
1988*4882a593Smuzhiyun 	    (old == SAS_END_DEVICE && new == SAS_SATA_PENDING))
1989*4882a593Smuzhiyun 		return true;
1990*4882a593Smuzhiyun 
1991*4882a593Smuzhiyun 	return false;
1992*4882a593Smuzhiyun }
1993*4882a593Smuzhiyun 
sas_rediscover_dev(struct domain_device * dev,int phy_id,bool last,int sibling)1994*4882a593Smuzhiyun static int sas_rediscover_dev(struct domain_device *dev, int phy_id,
1995*4882a593Smuzhiyun 			      bool last, int sibling)
1996*4882a593Smuzhiyun {
1997*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
1998*4882a593Smuzhiyun 	struct ex_phy *phy = &ex->ex_phy[phy_id];
1999*4882a593Smuzhiyun 	enum sas_device_type type = SAS_PHY_UNUSED;
2000*4882a593Smuzhiyun 	u8 sas_addr[SAS_ADDR_SIZE];
2001*4882a593Smuzhiyun 	char msg[80] = "";
2002*4882a593Smuzhiyun 	int res;
2003*4882a593Smuzhiyun 
2004*4882a593Smuzhiyun 	if (!last)
2005*4882a593Smuzhiyun 		sprintf(msg, ", part of a wide port with phy%02d", sibling);
2006*4882a593Smuzhiyun 
2007*4882a593Smuzhiyun 	pr_debug("ex %016llx rediscovering phy%02d%s\n",
2008*4882a593Smuzhiyun 		 SAS_ADDR(dev->sas_addr), phy_id, msg);
2009*4882a593Smuzhiyun 
2010*4882a593Smuzhiyun 	memset(sas_addr, 0, SAS_ADDR_SIZE);
2011*4882a593Smuzhiyun 	res = sas_get_phy_attached_dev(dev, phy_id, sas_addr, &type);
2012*4882a593Smuzhiyun 	switch (res) {
2013*4882a593Smuzhiyun 	case SMP_RESP_NO_PHY:
2014*4882a593Smuzhiyun 		phy->phy_state = PHY_NOT_PRESENT;
2015*4882a593Smuzhiyun 		sas_unregister_devs_sas_addr(dev, phy_id, last);
2016*4882a593Smuzhiyun 		return res;
2017*4882a593Smuzhiyun 	case SMP_RESP_PHY_VACANT:
2018*4882a593Smuzhiyun 		phy->phy_state = PHY_VACANT;
2019*4882a593Smuzhiyun 		sas_unregister_devs_sas_addr(dev, phy_id, last);
2020*4882a593Smuzhiyun 		return res;
2021*4882a593Smuzhiyun 	case SMP_RESP_FUNC_ACC:
2022*4882a593Smuzhiyun 		break;
2023*4882a593Smuzhiyun 	case -ECOMM:
2024*4882a593Smuzhiyun 		break;
2025*4882a593Smuzhiyun 	default:
2026*4882a593Smuzhiyun 		return res;
2027*4882a593Smuzhiyun 	}
2028*4882a593Smuzhiyun 
2029*4882a593Smuzhiyun 	if ((SAS_ADDR(sas_addr) == 0) || (res == -ECOMM)) {
2030*4882a593Smuzhiyun 		phy->phy_state = PHY_EMPTY;
2031*4882a593Smuzhiyun 		sas_unregister_devs_sas_addr(dev, phy_id, last);
2032*4882a593Smuzhiyun 		/*
2033*4882a593Smuzhiyun 		 * Even though the PHY is empty, for convenience we discover
2034*4882a593Smuzhiyun 		 * the PHY to update the PHY info, like negotiated linkrate.
2035*4882a593Smuzhiyun 		 */
2036*4882a593Smuzhiyun 		sas_ex_phy_discover(dev, phy_id);
2037*4882a593Smuzhiyun 		return res;
2038*4882a593Smuzhiyun 	} else if (SAS_ADDR(sas_addr) == SAS_ADDR(phy->attached_sas_addr) &&
2039*4882a593Smuzhiyun 		   dev_type_flutter(type, phy->attached_dev_type)) {
2040*4882a593Smuzhiyun 		struct domain_device *ata_dev = sas_ex_to_ata(dev, phy_id);
2041*4882a593Smuzhiyun 		char *action = "";
2042*4882a593Smuzhiyun 
2043*4882a593Smuzhiyun 		sas_ex_phy_discover(dev, phy_id);
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun 		if (ata_dev && phy->attached_dev_type == SAS_SATA_PENDING)
2046*4882a593Smuzhiyun 			action = ", needs recovery";
2047*4882a593Smuzhiyun 		pr_debug("ex %016llx phy%02d broadcast flutter%s\n",
2048*4882a593Smuzhiyun 			 SAS_ADDR(dev->sas_addr), phy_id, action);
2049*4882a593Smuzhiyun 		return res;
2050*4882a593Smuzhiyun 	}
2051*4882a593Smuzhiyun 
2052*4882a593Smuzhiyun 	/* we always have to delete the old device when we went here */
2053*4882a593Smuzhiyun 	pr_info("ex %016llx phy%02d replace %016llx\n",
2054*4882a593Smuzhiyun 		SAS_ADDR(dev->sas_addr), phy_id,
2055*4882a593Smuzhiyun 		SAS_ADDR(phy->attached_sas_addr));
2056*4882a593Smuzhiyun 	sas_unregister_devs_sas_addr(dev, phy_id, last);
2057*4882a593Smuzhiyun 
2058*4882a593Smuzhiyun 	return sas_discover_new(dev, phy_id);
2059*4882a593Smuzhiyun }
2060*4882a593Smuzhiyun 
2061*4882a593Smuzhiyun /**
2062*4882a593Smuzhiyun  * sas_rediscover - revalidate the domain.
2063*4882a593Smuzhiyun  * @dev:domain device to be detect.
2064*4882a593Smuzhiyun  * @phy_id: the phy id will be detected.
2065*4882a593Smuzhiyun  *
2066*4882a593Smuzhiyun  * NOTE: this process _must_ quit (return) as soon as any connection
2067*4882a593Smuzhiyun  * errors are encountered.  Connection recovery is done elsewhere.
2068*4882a593Smuzhiyun  * Discover process only interrogates devices in order to discover the
2069*4882a593Smuzhiyun  * domain.For plugging out, we un-register the device only when it is
2070*4882a593Smuzhiyun  * the last phy in the port, for other phys in this port, we just delete it
2071*4882a593Smuzhiyun  * from the port.For inserting, we do discovery when it is the
2072*4882a593Smuzhiyun  * first phy,for other phys in this port, we add it to the port to
2073*4882a593Smuzhiyun  * forming the wide-port.
2074*4882a593Smuzhiyun  */
sas_rediscover(struct domain_device * dev,const int phy_id)2075*4882a593Smuzhiyun static int sas_rediscover(struct domain_device *dev, const int phy_id)
2076*4882a593Smuzhiyun {
2077*4882a593Smuzhiyun 	struct expander_device *ex = &dev->ex_dev;
2078*4882a593Smuzhiyun 	struct ex_phy *changed_phy = &ex->ex_phy[phy_id];
2079*4882a593Smuzhiyun 	int res = 0;
2080*4882a593Smuzhiyun 	int i;
2081*4882a593Smuzhiyun 	bool last = true;	/* is this the last phy of the port */
2082*4882a593Smuzhiyun 
2083*4882a593Smuzhiyun 	pr_debug("ex %016llx phy%02d originated BROADCAST(CHANGE)\n",
2084*4882a593Smuzhiyun 		 SAS_ADDR(dev->sas_addr), phy_id);
2085*4882a593Smuzhiyun 
2086*4882a593Smuzhiyun 	if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) {
2087*4882a593Smuzhiyun 		for (i = 0; i < ex->num_phys; i++) {
2088*4882a593Smuzhiyun 			struct ex_phy *phy = &ex->ex_phy[i];
2089*4882a593Smuzhiyun 
2090*4882a593Smuzhiyun 			if (i == phy_id)
2091*4882a593Smuzhiyun 				continue;
2092*4882a593Smuzhiyun 			if (SAS_ADDR(phy->attached_sas_addr) ==
2093*4882a593Smuzhiyun 			    SAS_ADDR(changed_phy->attached_sas_addr)) {
2094*4882a593Smuzhiyun 				last = false;
2095*4882a593Smuzhiyun 				break;
2096*4882a593Smuzhiyun 			}
2097*4882a593Smuzhiyun 		}
2098*4882a593Smuzhiyun 		res = sas_rediscover_dev(dev, phy_id, last, i);
2099*4882a593Smuzhiyun 	} else
2100*4882a593Smuzhiyun 		res = sas_discover_new(dev, phy_id);
2101*4882a593Smuzhiyun 	return res;
2102*4882a593Smuzhiyun }
2103*4882a593Smuzhiyun 
2104*4882a593Smuzhiyun /**
2105*4882a593Smuzhiyun  * sas_ex_revalidate_domain - revalidate the domain
2106*4882a593Smuzhiyun  * @port_dev: port domain device.
2107*4882a593Smuzhiyun  *
2108*4882a593Smuzhiyun  * NOTE: this process _must_ quit (return) as soon as any connection
2109*4882a593Smuzhiyun  * errors are encountered.  Connection recovery is done elsewhere.
2110*4882a593Smuzhiyun  * Discover process only interrogates devices in order to discover the
2111*4882a593Smuzhiyun  * domain.
2112*4882a593Smuzhiyun  */
sas_ex_revalidate_domain(struct domain_device * port_dev)2113*4882a593Smuzhiyun int sas_ex_revalidate_domain(struct domain_device *port_dev)
2114*4882a593Smuzhiyun {
2115*4882a593Smuzhiyun 	int res;
2116*4882a593Smuzhiyun 	struct domain_device *dev = NULL;
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	res = sas_find_bcast_dev(port_dev, &dev);
2119*4882a593Smuzhiyun 	if (res == 0 && dev) {
2120*4882a593Smuzhiyun 		struct expander_device *ex = &dev->ex_dev;
2121*4882a593Smuzhiyun 		int i = 0, phy_id;
2122*4882a593Smuzhiyun 
2123*4882a593Smuzhiyun 		do {
2124*4882a593Smuzhiyun 			phy_id = -1;
2125*4882a593Smuzhiyun 			res = sas_find_bcast_phy(dev, &phy_id, i, true);
2126*4882a593Smuzhiyun 			if (phy_id == -1)
2127*4882a593Smuzhiyun 				break;
2128*4882a593Smuzhiyun 			res = sas_rediscover(dev, phy_id);
2129*4882a593Smuzhiyun 			i = phy_id + 1;
2130*4882a593Smuzhiyun 		} while (i < ex->num_phys);
2131*4882a593Smuzhiyun 	}
2132*4882a593Smuzhiyun 	return res;
2133*4882a593Smuzhiyun }
2134*4882a593Smuzhiyun 
sas_smp_handler(struct bsg_job * job,struct Scsi_Host * shost,struct sas_rphy * rphy)2135*4882a593Smuzhiyun void sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
2136*4882a593Smuzhiyun 		struct sas_rphy *rphy)
2137*4882a593Smuzhiyun {
2138*4882a593Smuzhiyun 	struct domain_device *dev;
2139*4882a593Smuzhiyun 	unsigned int rcvlen = 0;
2140*4882a593Smuzhiyun 	int ret = -EINVAL;
2141*4882a593Smuzhiyun 
2142*4882a593Smuzhiyun 	/* no rphy means no smp target support (ie aic94xx host) */
2143*4882a593Smuzhiyun 	if (!rphy)
2144*4882a593Smuzhiyun 		return sas_smp_host_handler(job, shost);
2145*4882a593Smuzhiyun 
2146*4882a593Smuzhiyun 	switch (rphy->identify.device_type) {
2147*4882a593Smuzhiyun 	case SAS_EDGE_EXPANDER_DEVICE:
2148*4882a593Smuzhiyun 	case SAS_FANOUT_EXPANDER_DEVICE:
2149*4882a593Smuzhiyun 		break;
2150*4882a593Smuzhiyun 	default:
2151*4882a593Smuzhiyun 		pr_err("%s: can we send a smp request to a device?\n",
2152*4882a593Smuzhiyun 		       __func__);
2153*4882a593Smuzhiyun 		goto out;
2154*4882a593Smuzhiyun 	}
2155*4882a593Smuzhiyun 
2156*4882a593Smuzhiyun 	dev = sas_find_dev_by_rphy(rphy);
2157*4882a593Smuzhiyun 	if (!dev) {
2158*4882a593Smuzhiyun 		pr_err("%s: fail to find a domain_device?\n", __func__);
2159*4882a593Smuzhiyun 		goto out;
2160*4882a593Smuzhiyun 	}
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun 	/* do we need to support multiple segments? */
2163*4882a593Smuzhiyun 	if (job->request_payload.sg_cnt > 1 ||
2164*4882a593Smuzhiyun 	    job->reply_payload.sg_cnt > 1) {
2165*4882a593Smuzhiyun 		pr_info("%s: multiple segments req %u, rsp %u\n",
2166*4882a593Smuzhiyun 			__func__, job->request_payload.payload_len,
2167*4882a593Smuzhiyun 			job->reply_payload.payload_len);
2168*4882a593Smuzhiyun 		goto out;
2169*4882a593Smuzhiyun 	}
2170*4882a593Smuzhiyun 
2171*4882a593Smuzhiyun 	ret = smp_execute_task_sg(dev, job->request_payload.sg_list,
2172*4882a593Smuzhiyun 			job->reply_payload.sg_list);
2173*4882a593Smuzhiyun 	if (ret >= 0) {
2174*4882a593Smuzhiyun 		/* bsg_job_done() requires the length received  */
2175*4882a593Smuzhiyun 		rcvlen = job->reply_payload.payload_len - ret;
2176*4882a593Smuzhiyun 		ret = 0;
2177*4882a593Smuzhiyun 	}
2178*4882a593Smuzhiyun 
2179*4882a593Smuzhiyun out:
2180*4882a593Smuzhiyun 	bsg_job_done(job, ret, rcvlen);
2181*4882a593Smuzhiyun }
2182