Blame view

drivers/ata/libata-pmp.c 26 KB
55716d264   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
3af9a77af   Tejun Heo   libata-pmp: imple...
2
3
4
5
6
  /*
   * libata-pmp.c - libata port multiplier support
   *
   * Copyright (c) 2007  SUSE Linux Products GmbH
   * Copyright (c) 2007  Tejun Heo <teheo@suse.de>
3af9a77af   Tejun Heo   libata-pmp: imple...
7
8
9
   */
  
  #include <linux/kernel.h>
38789fda2   Paul Gortmaker   ide/ata: Add expo...
10
  #include <linux/export.h>
3af9a77af   Tejun Heo   libata-pmp: imple...
11
  #include <linux/libata.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
12
  #include <linux/slab.h>
3af9a77af   Tejun Heo   libata-pmp: imple...
13
  #include "libata.h"
d9027470b   Gwendal Grignou   [libata] Add ATA ...
14
  #include "libata-transport.h"
3af9a77af   Tejun Heo   libata-pmp: imple...
15

48515f6c0   Tejun Heo   libata: separate ...
16
17
18
19
20
21
22
  const struct ata_port_operations sata_pmp_port_ops = {
  	.inherits		= &sata_port_ops,
  	.pmp_prereset		= ata_std_prereset,
  	.pmp_hardreset		= sata_std_hardreset,
  	.pmp_postreset		= ata_std_postreset,
  	.error_handler		= sata_pmp_error_handler,
  };
3af9a77af   Tejun Heo   libata-pmp: imple...
23
24
25
26
27
28
  /**
   *	sata_pmp_read - read PMP register
   *	@link: link to read PMP register for
   *	@reg: register to read
   *	@r_val: resulting value
   *
b06ce3e51   Tejun Heo   libata: use ata_e...
29
   *	Read PMP register.
3af9a77af   Tejun Heo   libata-pmp: imple...
30
31
32
33
34
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
b06ce3e51   Tejun Heo   libata: use ata_e...
35
   *	0 on success, AC_ERR_* mask on failure.
3af9a77af   Tejun Heo   libata-pmp: imple...
36
   */
b06ce3e51   Tejun Heo   libata: use ata_e...
37
  static unsigned int sata_pmp_read(struct ata_link *link, int reg, u32 *r_val)
3af9a77af   Tejun Heo   libata-pmp: imple...
38
39
40
  {
  	struct ata_port *ap = link->ap;
  	struct ata_device *pmp_dev = ap->link.device;
b06ce3e51   Tejun Heo   libata: use ata_e...
41
42
43
44
45
46
  	struct ata_taskfile tf;
  	unsigned int err_mask;
  
  	ata_tf_init(pmp_dev, &tf);
  	tf.command = ATA_CMD_PMP_READ;
  	tf.protocol = ATA_PROT_NODATA;
39f25e70c   Mark Lord   libata-pmp: clear...
47
  	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48;
b06ce3e51   Tejun Heo   libata: use ata_e...
48
49
50
51
  	tf.feature = reg;
  	tf.device = link->pmp;
  
  	err_mask = ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
bf1bff6fa   Tejun Heo   libata: increase ...
52
  				     SATA_PMP_RW_TIMEOUT);
b06ce3e51   Tejun Heo   libata: use ata_e...
53
54
55
56
57
  	if (err_mask)
  		return err_mask;
  
  	*r_val = tf.nsect | tf.lbal << 8 | tf.lbam << 16 | tf.lbah << 24;
  	return 0;
3af9a77af   Tejun Heo   libata-pmp: imple...
58
59
60
61
62
63
64
65
  }
  
  /**
   *	sata_pmp_write - write PMP register
   *	@link: link to write PMP register for
   *	@reg: register to write
   *	@r_val: value to write
   *
b06ce3e51   Tejun Heo   libata: use ata_e...
66
   *	Write PMP register.
3af9a77af   Tejun Heo   libata-pmp: imple...
67
68
69
70
71
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
b06ce3e51   Tejun Heo   libata: use ata_e...
72
   *	0 on success, AC_ERR_* mask on failure.
3af9a77af   Tejun Heo   libata-pmp: imple...
73
   */
b06ce3e51   Tejun Heo   libata: use ata_e...
74
  static unsigned int sata_pmp_write(struct ata_link *link, int reg, u32 val)
3af9a77af   Tejun Heo   libata-pmp: imple...
75
76
77
  {
  	struct ata_port *ap = link->ap;
  	struct ata_device *pmp_dev = ap->link.device;
b06ce3e51   Tejun Heo   libata: use ata_e...
78
79
80
81
82
  	struct ata_taskfile tf;
  
  	ata_tf_init(pmp_dev, &tf);
  	tf.command = ATA_CMD_PMP_WRITE;
  	tf.protocol = ATA_PROT_NODATA;
39f25e70c   Mark Lord   libata-pmp: clear...
83
  	tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE | ATA_TFLAG_LBA48;
b06ce3e51   Tejun Heo   libata: use ata_e...
84
85
86
87
88
89
90
91
  	tf.feature = reg;
  	tf.device = link->pmp;
  	tf.nsect = val & 0xff;
  	tf.lbal = (val >> 8) & 0xff;
  	tf.lbam = (val >> 16) & 0xff;
  	tf.lbah = (val >> 24) & 0xff;
  
  	return ata_exec_internal(pmp_dev, &tf, NULL, DMA_NONE, NULL, 0,
bf1bff6fa   Tejun Heo   libata: increase ...
92
  				 SATA_PMP_RW_TIMEOUT);
3af9a77af   Tejun Heo   libata-pmp: imple...
93
94
95
  }
  
  /**
31f883844   Tejun Heo   libata-pmp: imple...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
   *	sata_pmp_qc_defer_cmd_switch - qc_defer for command switching PMP
   *	@qc: ATA command in question
   *
   *	A host which has command switching PMP support cannot issue
   *	commands to multiple links simultaneously.
   *
   *	LOCKING:
   *	spin_lock_irqsave(host lock)
   *
   *	RETURNS:
   *	ATA_DEFER_* if deferring is needed, 0 otherwise.
   */
  int sata_pmp_qc_defer_cmd_switch(struct ata_queued_cmd *qc)
  {
  	struct ata_link *link = qc->dev->link;
  	struct ata_port *ap = link->ap;
  
  	if (ap->excl_link == NULL || ap->excl_link == link) {
  		if (ap->nr_active_links == 0 || ata_link_active(link)) {
  			qc->flags |= ATA_QCFLAG_CLEAR_EXCL;
  			return ata_std_qc_defer(qc);
  		}
  
  		ap->excl_link = link;
  	}
  
  	return ATA_DEFER_PORT;
  }
  
  /**
3af9a77af   Tejun Heo   libata-pmp: imple...
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
   *	sata_pmp_scr_read - read PSCR
   *	@link: ATA link to read PSCR for
   *	@reg: PSCR to read
   *	@r_val: resulting value
   *
   *	Read PSCR @reg into @r_val for @link, to be called from
   *	ata_scr_read().
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno on failure.
   */
  int sata_pmp_scr_read(struct ata_link *link, int reg, u32 *r_val)
  {
b06ce3e51   Tejun Heo   libata: use ata_e...
142
  	unsigned int err_mask;
3af9a77af   Tejun Heo   libata-pmp: imple...
143
144
  	if (reg > SATA_PMP_PSCR_CONTROL)
  		return -EINVAL;
b06ce3e51   Tejun Heo   libata: use ata_e...
145
146
  	err_mask = sata_pmp_read(link, reg, r_val);
  	if (err_mask) {
a9a79dfec   Joe Perches   ata: Convert ata_...
147
148
149
  		ata_link_warn(link, "failed to read SCR %d (Emask=0x%x)
  ",
  			      reg, err_mask);
b06ce3e51   Tejun Heo   libata: use ata_e...
150
151
152
  		return -EIO;
  	}
  	return 0;
3af9a77af   Tejun Heo   libata-pmp: imple...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
  }
  
  /**
   *	sata_pmp_scr_write - write PSCR
   *	@link: ATA link to write PSCR for
   *	@reg: PSCR to write
   *	@val: value to be written
   *
   *	Write @val to PSCR @reg for @link, to be called from
   *	ata_scr_write() and ata_scr_write_flush().
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno on failure.
   */
  int sata_pmp_scr_write(struct ata_link *link, int reg, u32 val)
  {
b06ce3e51   Tejun Heo   libata: use ata_e...
172
  	unsigned int err_mask;
3af9a77af   Tejun Heo   libata-pmp: imple...
173
174
  	if (reg > SATA_PMP_PSCR_CONTROL)
  		return -EINVAL;
b06ce3e51   Tejun Heo   libata: use ata_e...
175
176
  	err_mask = sata_pmp_write(link, reg, val);
  	if (err_mask) {
a9a79dfec   Joe Perches   ata: Convert ata_...
177
178
179
  		ata_link_warn(link, "failed to write SCR %d (Emask=0x%x)
  ",
  			      reg, err_mask);
b06ce3e51   Tejun Heo   libata: use ata_e...
180
181
182
  		return -EIO;
  	}
  	return 0;
3af9a77af   Tejun Heo   libata-pmp: imple...
183
184
185
  }
  
  /**
6c8ea89ce   Tejun Heo   libata: implement...
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
   *	sata_pmp_set_lpm - configure LPM for a PMP link
   *	@link: PMP link to configure LPM for
   *	@policy: target LPM policy
   *	@hints: LPM hints
   *
   *	Configure LPM for @link.  This function will contain any PMP
   *	specific workarounds if necessary.
   *
   *	LOCKING:
   *	EH context.
   *
   *	RETURNS:
   *	0 on success, -errno on failure.
   */
  int sata_pmp_set_lpm(struct ata_link *link, enum ata_lpm_policy policy,
  		     unsigned hints)
  {
  	return sata_link_scr_lpm(link, policy, true);
  }
  
  /**
3af9a77af   Tejun Heo   libata-pmp: imple...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
   *	sata_pmp_read_gscr - read GSCR block of SATA PMP
   *	@dev: PMP device
   *	@gscr: buffer to read GSCR block into
   *
   *	Read selected PMP GSCRs from the PMP at @dev.  This will serve
   *	as configuration and identification info for the PMP.
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno on failure.
   */
  static int sata_pmp_read_gscr(struct ata_device *dev, u32 *gscr)
  {
  	static const int gscr_to_read[] = { 0, 1, 2, 32, 33, 64, 96 };
b06ce3e51   Tejun Heo   libata: use ata_e...
223
  	int i;
3af9a77af   Tejun Heo   libata-pmp: imple...
224
225
226
  
  	for (i = 0; i < ARRAY_SIZE(gscr_to_read); i++) {
  		int reg = gscr_to_read[i];
b06ce3e51   Tejun Heo   libata: use ata_e...
227
  		unsigned int err_mask;
3af9a77af   Tejun Heo   libata-pmp: imple...
228

b06ce3e51   Tejun Heo   libata: use ata_e...
229
230
  		err_mask = sata_pmp_read(dev->link, reg, &gscr[reg]);
  		if (err_mask) {
a9a79dfec   Joe Perches   ata: Convert ata_...
231
232
233
  			ata_dev_err(dev, "failed to read PMP GSCR[%d] (Emask=0x%x)
  ",
  				    reg, err_mask);
b06ce3e51   Tejun Heo   libata: use ata_e...
234
  			return -EIO;
3af9a77af   Tejun Heo   libata-pmp: imple...
235
236
237
238
239
240
241
242
243
  		}
  	}
  
  	return 0;
  }
  
  static const char *sata_pmp_spec_rev_str(const u32 *gscr)
  {
  	u32 rev = gscr[SATA_PMP_GSCR_REV];
deeb003e5   Shane Huang   libata: add SATA ...
244
245
  	if (rev & (1 << 3))
  		return "1.2";
3af9a77af   Tejun Heo   libata-pmp: imple...
246
247
248
249
250
251
  	if (rev & (1 << 2))
  		return "1.1";
  	if (rev & (1 << 1))
  		return "1.0";
  	return "<unknown>";
  }
4f2c77485   Grant Grundler   [libata] Disable ...
252
  #define PMP_GSCR_SII_POL 129
3af9a77af   Tejun Heo   libata-pmp: imple...
253
254
255
256
  static int sata_pmp_configure(struct ata_device *dev, int print_info)
  {
  	struct ata_port *ap = dev->link->ap;
  	u32 *gscr = dev->gscr;
4f2c77485   Grant Grundler   [libata] Disable ...
257
258
  	u16 vendor = sata_pmp_gscr_vendor(gscr);
  	u16 devid = sata_pmp_gscr_devid(gscr);
b06ce3e51   Tejun Heo   libata: use ata_e...
259
  	unsigned int err_mask = 0;
3af9a77af   Tejun Heo   libata-pmp: imple...
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  	const char *reason;
  	int nr_ports, rc;
  
  	nr_ports = sata_pmp_gscr_ports(gscr);
  
  	if (nr_ports <= 0 || nr_ports > SATA_PMP_MAX_PORTS) {
  		rc = -EINVAL;
  		reason = "invalid nr_ports";
  		goto fail;
  	}
  
  	if ((ap->flags & ATA_FLAG_AN) &&
  	    (gscr[SATA_PMP_GSCR_FEAT] & SATA_PMP_FEAT_NOTIFY))
  		dev->flags |= ATA_DFLAG_AN;
  
  	/* monitor SERR_PHYRDY_CHG on fan-out ports */
b06ce3e51   Tejun Heo   libata: use ata_e...
276
277
278
279
  	err_mask = sata_pmp_write(dev->link, SATA_PMP_GSCR_ERROR_EN,
  				  SERR_PHYRDY_CHG);
  	if (err_mask) {
  		rc = -EIO;
3af9a77af   Tejun Heo   libata-pmp: imple...
280
281
282
  		reason = "failed to write GSCR_ERROR_EN";
  		goto fail;
  	}
4f2c77485   Grant Grundler   [libata] Disable ...
283
284
  	/* Disable sending Early R_OK.
  	 * With "cached read" HDD testing and multiple ports busy on a SATA
8ffff94d2   Terry Suereth   libata: apply beh...
285
  	 * host controller, 3x26 PMP will very rarely drop a deferred
4f2c77485   Grant Grundler   [libata] Disable ...
286
287
288
  	 * R_OK that was intended for the host. Symptom will be all
  	 * 5 drives under test will timeout, get reset, and recover.
  	 */
8ffff94d2   Terry Suereth   libata: apply beh...
289
  	if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
4f2c77485   Grant Grundler   [libata] Disable ...
290
291
292
293
294
  		u32 reg;
  
  		err_mask = sata_pmp_read(&ap->link, PMP_GSCR_SII_POL, &reg);
  		if (err_mask) {
  			rc = -EIO;
8ffff94d2   Terry Suereth   libata: apply beh...
295
  			reason = "failed to read Sil3x26 Private Register";
4f2c77485   Grant Grundler   [libata] Disable ...
296
297
298
299
300
301
  			goto fail;
  		}
  		reg &= ~0x1;
  		err_mask = sata_pmp_write(&ap->link, PMP_GSCR_SII_POL, reg);
  		if (err_mask) {
  			rc = -EIO;
8ffff94d2   Terry Suereth   libata: apply beh...
302
  			reason = "failed to write Sil3x26 Private Register";
4f2c77485   Grant Grundler   [libata] Disable ...
303
304
305
  			goto fail;
  		}
  	}
3af9a77af   Tejun Heo   libata-pmp: imple...
306
  	if (print_info) {
a9a79dfec   Joe Perches   ata: Convert ata_...
307
308
309
310
311
312
313
  		ata_dev_info(dev, "Port Multiplier %s, "
  			     "0x%04x:0x%04x r%d, %d ports, feat 0x%x/0x%x
  ",
  			     sata_pmp_spec_rev_str(gscr), vendor, devid,
  			     sata_pmp_gscr_rev(gscr),
  			     nr_ports, gscr[SATA_PMP_GSCR_FEAT_EN],
  			     gscr[SATA_PMP_GSCR_FEAT]);
3af9a77af   Tejun Heo   libata-pmp: imple...
314
315
  
  		if (!(dev->flags & ATA_DFLAG_AN))
a9a79dfec   Joe Perches   ata: Convert ata_...
316
  			ata_dev_info(dev,
3af9a77af   Tejun Heo   libata-pmp: imple...
317
  				"Asynchronous notification not supported, "
a9a79dfec   Joe Perches   ata: Convert ata_...
318
319
  				"hotplug won't work on fan-out ports. Use warm-plug instead.
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
320
321
322
323
324
  	}
  
  	return 0;
  
   fail:
a9a79dfec   Joe Perches   ata: Convert ata_...
325
326
327
328
  	ata_dev_err(dev,
  		    "failed to configure Port Multiplier (%s, Emask=0x%x)
  ",
  		    reason, err_mask);
3af9a77af   Tejun Heo   libata-pmp: imple...
329
330
  	return rc;
  }
d9027470b   Gwendal Grignou   [libata] Add ATA ...
331
  static int sata_pmp_init_links (struct ata_port *ap, int nr_ports)
3af9a77af   Tejun Heo   libata-pmp: imple...
332
333
  {
  	struct ata_link *pmp_link = ap->pmp_link;
d9027470b   Gwendal Grignou   [libata] Add ATA ...
334
  	int i, err;
3af9a77af   Tejun Heo   libata-pmp: imple...
335
336
  
  	if (!pmp_link) {
6396bb221   Kees Cook   treewide: kzalloc...
337
  		pmp_link = kcalloc(SATA_PMP_MAX_PORTS, sizeof(pmp_link[0]),
3af9a77af   Tejun Heo   libata-pmp: imple...
338
339
340
341
342
343
344
345
  				   GFP_NOIO);
  		if (!pmp_link)
  			return -ENOMEM;
  
  		for (i = 0; i < SATA_PMP_MAX_PORTS; i++)
  			ata_link_init(ap, &pmp_link[i], i);
  
  		ap->pmp_link = pmp_link;
d9027470b   Gwendal Grignou   [libata] Add ATA ...
346
347
348
349
350
351
352
  
  		for (i = 0; i < SATA_PMP_MAX_PORTS; i++) {
  			err = ata_tlink_add(&pmp_link[i]);
  			if (err) {
  				goto err_tlink;
  			}
  		}
3af9a77af   Tejun Heo   libata-pmp: imple...
353
354
355
356
357
358
359
  	}
  
  	for (i = 0; i < nr_ports; i++) {
  		struct ata_link *link = &pmp_link[i];
  		struct ata_eh_context *ehc = &link->eh_context;
  
  		link->flags = 0;
b558edddb   Tejun Heo   libata: kill ata_...
360
  		ehc->i.probe_mask |= ATA_ALL_DEVICES;
cf4806265   Tejun Heo   libata: prefer ha...
361
  		ehc->i.action |= ATA_EH_RESET;
3af9a77af   Tejun Heo   libata-pmp: imple...
362
363
364
  	}
  
  	return 0;
d9027470b   Gwendal Grignou   [libata] Add ATA ...
365
366
367
368
369
370
    err_tlink:
  	while (--i >= 0)
  		ata_tlink_delete(&pmp_link[i]);
  	kfree(pmp_link);
  	ap->pmp_link = NULL;
  	return err;
3af9a77af   Tejun Heo   libata-pmp: imple...
371
372
373
374
375
376
377
378
  }
  
  static void sata_pmp_quirks(struct ata_port *ap)
  {
  	u32 *gscr = ap->link.device->gscr;
  	u16 vendor = sata_pmp_gscr_vendor(gscr);
  	u16 devid = sata_pmp_gscr_devid(gscr);
  	struct ata_link *link;
8ffff94d2   Terry Suereth   libata: apply beh...
379
380
  	if (vendor == 0x1095 && (devid == 0x3726 || devid == 0x3826)) {
  		/* sil3x26 quirks */
1eca4365b   Tejun Heo   libata: beef up i...
381
  		ata_for_each_link(link, ap, EDGE) {
6c8ea89ce   Tejun Heo   libata: implement...
382
383
  			/* link reports offline after LPM */
  			link->flags |= ATA_LFLAG_NO_LPM;
7a87718d9   Tejun Heo   libata: skip SRST...
384
385
386
387
  			/*
  			 * Class code report is unreliable and SRST times
  			 * out under certain configurations.
  			 */
3af9a77af   Tejun Heo   libata-pmp: imple...
388
  			if (link->pmp < 5)
7a87718d9   Tejun Heo   libata: skip SRST...
389
390
  				link->flags |= ATA_LFLAG_NO_SRST |
  					       ATA_LFLAG_ASSUME_ATA;
3af9a77af   Tejun Heo   libata-pmp: imple...
391
392
393
394
395
396
397
  
  			/* port 5 is for SEMB device and it doesn't like SRST */
  			if (link->pmp == 5)
  				link->flags |= ATA_LFLAG_NO_SRST |
  					       ATA_LFLAG_ASSUME_SEMB;
  		}
  	} else if (vendor == 0x1095 && devid == 0x4723) {
7a87718d9   Tejun Heo   libata: skip SRST...
398
399
400
401
402
403
404
405
406
407
408
  		/*
  		 * sil4723 quirks
  		 *
  		 * Link reports offline after LPM.  Class code report is
  		 * unreliable.  SIMG PMPs never got SRST reliable and the
  		 * config device at port 2 locks up on SRST.
  		 */
  		ata_for_each_link(link, ap, EDGE)
  			link->flags |= ATA_LFLAG_NO_LPM |
  				       ATA_LFLAG_NO_SRST |
  				       ATA_LFLAG_ASSUME_ATA;
3af9a77af   Tejun Heo   libata-pmp: imple...
409
410
  	} else if (vendor == 0x1095 && devid == 0x4726) {
  		/* sil4726 quirks */
1eca4365b   Tejun Heo   libata: beef up i...
411
  		ata_for_each_link(link, ap, EDGE) {
6c8ea89ce   Tejun Heo   libata: implement...
412
413
  			/* link reports offline after LPM */
  			link->flags |= ATA_LFLAG_NO_LPM;
8048307db   Tejun Heo   libata-pmp: 4726 ...
414
415
416
417
  			/* Class code report is unreliable and SRST
  			 * times out under certain configurations.
  			 * Config device can be at port 0 or 5 and
  			 * locks up on SRST.
3af9a77af   Tejun Heo   libata-pmp: imple...
418
  			 */
8048307db   Tejun Heo   libata-pmp: 4726 ...
419
  			if (link->pmp <= 5)
3af9a77af   Tejun Heo   libata-pmp: imple...
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  				link->flags |= ATA_LFLAG_NO_SRST |
  					       ATA_LFLAG_ASSUME_ATA;
  
  			/* Port 6 is for SEMB device which doesn't
  			 * like SRST either.
  			 */
  			if (link->pmp == 6)
  				link->flags |= ATA_LFLAG_NO_SRST |
  					       ATA_LFLAG_ASSUME_SEMB;
  		}
  	} else if (vendor == 0x1095 && (devid == 0x5723 || devid == 0x5733 ||
  					devid == 0x5734 || devid == 0x5744)) {
  		/* sil5723/5744 quirks */
  
  		/* sil5723/5744 has either two or three downstream
  		 * ports depending on operation mode.  The last port
  		 * is empty if any actual IO device is available or
  		 * occupied by a pseudo configuration device
  		 * otherwise.  Don't try hard to recover it.
  		 */
  		ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY;
efb9e0f4f   Denis V. Lunev   ata: enable quirk...
441
442
443
444
445
  	} else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) {
  		/*
  		 * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350?
  		 * 0x0325: jmicron JMB394.
  		 */
0afc6f5ba   Pavel Herrmann   libata-pmp: add s...
446
447
448
449
450
451
452
453
  		ata_for_each_link(link, ap, EDGE) {
  			/* SRST breaks detection and disks get misclassified
  			 * LPM disabled to avoid potential problems
  			 */
  			link->flags |= ATA_LFLAG_NO_LPM |
  				       ATA_LFLAG_NO_SRST |
  				       ATA_LFLAG_ASSUME_ATA;
  		}
945b47441   Lior Amsalem   ata: pmp: add qui...
454
455
456
457
458
459
460
  	} else if (vendor == 0x11ab && devid == 0x4140) {
  		/* Marvell 4140 quirks */
  		ata_for_each_link(link, ap, EDGE) {
  			/* port 4 is for SEMB device and it doesn't like SRST */
  			if (link->pmp == 4)
  				link->flags |= ATA_LFLAG_DISABLED;
  		}
3af9a77af   Tejun Heo   libata-pmp: imple...
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
  	}
  }
  
  /**
   *	sata_pmp_attach - attach a SATA PMP device
   *	@dev: SATA PMP device to attach
   *
   *	Configure and attach SATA PMP device @dev.  This function is
   *	also responsible for allocating and initializing PMP links.
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno on failure.
   */
  int sata_pmp_attach(struct ata_device *dev)
  {
  	struct ata_link *link = dev->link;
  	struct ata_port *ap = link->ap;
  	unsigned long flags;
  	struct ata_link *tlink;
  	int rc;
  
  	/* is it hanging off the right place? */
071f44b1d   Tejun Heo   libata: implement...
486
  	if (!sata_pmp_supported(ap)) {
a9a79dfec   Joe Perches   ata: Convert ata_...
487
488
  		ata_dev_err(dev, "host does not support Port Multiplier
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
489
490
491
492
  		return -EINVAL;
  	}
  
  	if (!ata_is_host_link(link)) {
a9a79dfec   Joe Perches   ata: Convert ata_...
493
494
  		ata_dev_err(dev, "Port Multipliers cannot be nested
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
495
496
497
498
  		return -EINVAL;
  	}
  
  	if (dev->devno) {
a9a79dfec   Joe Perches   ata: Convert ata_...
499
500
  		ata_dev_err(dev, "Port Multiplier must be the first device
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  		return -EINVAL;
  	}
  
  	WARN_ON(link->pmp != 0);
  	link->pmp = SATA_PMP_CTRL_PORT;
  
  	/* read GSCR block */
  	rc = sata_pmp_read_gscr(dev, dev->gscr);
  	if (rc)
  		goto fail;
  
  	/* config PMP */
  	rc = sata_pmp_configure(dev, 1);
  	if (rc)
  		goto fail;
  
  	rc = sata_pmp_init_links(ap, sata_pmp_gscr_ports(dev->gscr));
  	if (rc) {
a9a79dfec   Joe Perches   ata: Convert ata_...
519
520
  		ata_dev_info(dev, "failed to initialize PMP links
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
521
522
523
524
525
526
527
528
529
530
531
532
533
  		goto fail;
  	}
  
  	/* attach it */
  	spin_lock_irqsave(ap->lock, flags);
  	WARN_ON(ap->nr_pmp_links);
  	ap->nr_pmp_links = sata_pmp_gscr_ports(dev->gscr);
  	spin_unlock_irqrestore(ap->lock, flags);
  
  	sata_pmp_quirks(ap);
  
  	if (ap->ops->pmp_attach)
  		ap->ops->pmp_attach(ap);
1eca4365b   Tejun Heo   libata: beef up i...
534
  	ata_for_each_link(tlink, ap, EDGE)
3af9a77af   Tejun Heo   libata-pmp: imple...
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
  		sata_link_init_spd(tlink);
  
  	return 0;
  
   fail:
  	link->pmp = 0;
  	return rc;
  }
  
  /**
   *	sata_pmp_detach - detach a SATA PMP device
   *	@dev: SATA PMP device to detach
   *
   *	Detach SATA PMP device @dev.  This function is also
   *	responsible for deconfiguring PMP links.
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   */
  static void sata_pmp_detach(struct ata_device *dev)
  {
  	struct ata_link *link = dev->link;
  	struct ata_port *ap = link->ap;
  	struct ata_link *tlink;
  	unsigned long flags;
a9a79dfec   Joe Perches   ata: Convert ata_...
560
561
  	ata_dev_info(dev, "Port Multiplier detaching
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
562
563
564
565
566
567
  
  	WARN_ON(!ata_is_host_link(link) || dev->devno ||
  		link->pmp != SATA_PMP_CTRL_PORT);
  
  	if (ap->ops->pmp_detach)
  		ap->ops->pmp_detach(ap);
1eca4365b   Tejun Heo   libata: beef up i...
568
  	ata_for_each_link(tlink, ap, EDGE)
3af9a77af   Tejun Heo   libata-pmp: imple...
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
  		ata_eh_detach_dev(tlink->device);
  
  	spin_lock_irqsave(ap->lock, flags);
  	ap->nr_pmp_links = 0;
  	link->pmp = 0;
  	spin_unlock_irqrestore(ap->lock, flags);
  }
  
  /**
   *	sata_pmp_same_pmp - does new GSCR matches the configured PMP?
   *	@dev: PMP device to compare against
   *	@new_gscr: GSCR block of the new device
   *
   *	Compare @new_gscr against @dev and determine whether @dev is
   *	the PMP described by @new_gscr.
   *
   *	LOCKING:
   *	None.
   *
   *	RETURNS:
   *	1 if @dev matches @new_gscr, 0 otherwise.
   */
  static int sata_pmp_same_pmp(struct ata_device *dev, const u32 *new_gscr)
  {
  	const u32 *old_gscr = dev->gscr;
  	u16 old_vendor, new_vendor, old_devid, new_devid;
  	int old_nr_ports, new_nr_ports;
  
  	old_vendor = sata_pmp_gscr_vendor(old_gscr);
  	new_vendor = sata_pmp_gscr_vendor(new_gscr);
  	old_devid = sata_pmp_gscr_devid(old_gscr);
  	new_devid = sata_pmp_gscr_devid(new_gscr);
  	old_nr_ports = sata_pmp_gscr_ports(old_gscr);
  	new_nr_ports = sata_pmp_gscr_ports(new_gscr);
  
  	if (old_vendor != new_vendor) {
a9a79dfec   Joe Perches   ata: Convert ata_...
605
606
607
608
  		ata_dev_info(dev,
  			     "Port Multiplier vendor mismatch '0x%x' != '0x%x'
  ",
  			     old_vendor, new_vendor);
3af9a77af   Tejun Heo   libata-pmp: imple...
609
610
611
612
  		return 0;
  	}
  
  	if (old_devid != new_devid) {
a9a79dfec   Joe Perches   ata: Convert ata_...
613
614
615
616
  		ata_dev_info(dev,
  			     "Port Multiplier device ID mismatch '0x%x' != '0x%x'
  ",
  			     old_devid, new_devid);
3af9a77af   Tejun Heo   libata-pmp: imple...
617
618
619
620
  		return 0;
  	}
  
  	if (old_nr_ports != new_nr_ports) {
a9a79dfec   Joe Perches   ata: Convert ata_...
621
622
623
624
  		ata_dev_info(dev,
  			     "Port Multiplier nr_ports mismatch '0x%x' != '0x%x'
  ",
  			     old_nr_ports, new_nr_ports);
3af9a77af   Tejun Heo   libata-pmp: imple...
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
  		return 0;
  	}
  
  	return 1;
  }
  
  /**
   *	sata_pmp_revalidate - revalidate SATA PMP
   *	@dev: PMP device to revalidate
   *	@new_class: new class code
   *
   *	Re-read GSCR block and make sure @dev is still attached to the
   *	port and properly configured.
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno otherwise.
   */
  static int sata_pmp_revalidate(struct ata_device *dev, unsigned int new_class)
  {
  	struct ata_link *link = dev->link;
  	struct ata_port *ap = link->ap;
  	u32 *gscr = (void *)ap->sector_buf;
  	int rc;
  
  	DPRINTK("ENTER
  ");
  
  	ata_eh_about_to_do(link, NULL, ATA_EH_REVALIDATE);
  
  	if (!ata_dev_enabled(dev)) {
  		rc = -ENODEV;
  		goto fail;
  	}
  
  	/* wrong class? */
  	if (ata_class_enabled(new_class) && new_class != ATA_DEV_PMP) {
  		rc = -ENODEV;
  		goto fail;
  	}
  
  	/* read GSCR */
  	rc = sata_pmp_read_gscr(dev, gscr);
  	if (rc)
  		goto fail;
  
  	/* is the pmp still there? */
  	if (!sata_pmp_same_pmp(dev, gscr)) {
  		rc = -ENODEV;
  		goto fail;
  	}
  
  	memcpy(dev->gscr, gscr, sizeof(gscr[0]) * SATA_PMP_GSCR_DWORDS);
  
  	rc = sata_pmp_configure(dev, 0);
  	if (rc)
  		goto fail;
  
  	ata_eh_done(link, NULL, ATA_EH_REVALIDATE);
  
  	DPRINTK("EXIT, rc=0
  ");
  	return 0;
  
   fail:
a9a79dfec   Joe Perches   ata: Convert ata_...
692
693
  	ata_dev_err(dev, "PMP revalidation failed (errno=%d)
  ", rc);
3af9a77af   Tejun Heo   libata-pmp: imple...
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
  	DPRINTK("EXIT, rc=%d
  ", rc);
  	return rc;
  }
  
  /**
   *	sata_pmp_revalidate_quick - revalidate SATA PMP quickly
   *	@dev: PMP device to revalidate
   *
   *	Make sure the attached PMP is accessible.
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno otherwise.
   */
  static int sata_pmp_revalidate_quick(struct ata_device *dev)
  {
b06ce3e51   Tejun Heo   libata: use ata_e...
713
  	unsigned int err_mask;
3af9a77af   Tejun Heo   libata-pmp: imple...
714
  	u32 prod_id;
3af9a77af   Tejun Heo   libata-pmp: imple...
715

b06ce3e51   Tejun Heo   libata: use ata_e...
716
717
  	err_mask = sata_pmp_read(dev->link, SATA_PMP_GSCR_PROD_ID, &prod_id);
  	if (err_mask) {
a9a79dfec   Joe Perches   ata: Convert ata_...
718
719
720
721
  		ata_dev_err(dev,
  			    "failed to read PMP product ID (Emask=0x%x)
  ",
  			    err_mask);
b06ce3e51   Tejun Heo   libata: use ata_e...
722
  		return -EIO;
3af9a77af   Tejun Heo   libata-pmp: imple...
723
724
725
  	}
  
  	if (prod_id != dev->gscr[SATA_PMP_GSCR_PROD_ID]) {
a9a79dfec   Joe Perches   ata: Convert ata_...
726
727
  		ata_dev_err(dev, "PMP product ID mismatch
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  		/* something weird is going on, request full PMP recovery */
  		return -EIO;
  	}
  
  	return 0;
  }
  
  /**
   *	sata_pmp_eh_recover_pmp - recover PMP
   *	@ap: ATA port PMP is attached to
   *	@prereset: prereset method (can be NULL)
   *	@softreset: softreset method
   *	@hardreset: hardreset method
   *	@postreset: postreset method (can be NULL)
   *
   *	Recover PMP attached to @ap.  Recovery procedure is somewhat
   *	similar to that of ata_eh_recover() except that reset should
   *	always be performed in hard->soft sequence and recovery
   *	failure results in PMP detachment.
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno on failure.
   */
  static int sata_pmp_eh_recover_pmp(struct ata_port *ap,
  		ata_prereset_fn_t prereset, ata_reset_fn_t softreset,
  		ata_reset_fn_t hardreset, ata_postreset_fn_t postreset)
  {
  	struct ata_link *link = &ap->link;
  	struct ata_eh_context *ehc = &link->eh_context;
  	struct ata_device *dev = link->device;
  	int tries = ATA_EH_PMP_TRIES;
  	int detach = 0, rc = 0;
  	int reval_failed = 0;
  
  	DPRINTK("ENTER
  ");
  
  	if (dev->flags & ATA_DFLAG_DETACH) {
  		detach = 1;
8305f72f9   Kai-Heng Feng   libata: Return co...
770
  		rc = -ENODEV;
3af9a77af   Tejun Heo   libata-pmp: imple...
771
772
773
774
775
  		goto fail;
  	}
  
   retry:
  	ehc->classes[0] = ATA_DEV_UNKNOWN;
cf4806265   Tejun Heo   libata: prefer ha...
776
  	if (ehc->i.action & ATA_EH_RESET) {
3af9a77af   Tejun Heo   libata-pmp: imple...
777
  		struct ata_link *tlink;
3af9a77af   Tejun Heo   libata-pmp: imple...
778
  		/* reset */
3af9a77af   Tejun Heo   libata-pmp: imple...
779
780
781
  		rc = ata_eh_reset(link, 0, prereset, softreset, hardreset,
  				  postreset);
  		if (rc) {
a9a79dfec   Joe Perches   ata: Convert ata_...
782
783
  			ata_link_err(link, "failed to reset PMP, giving up
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
784
785
  			goto fail;
  		}
3af9a77af   Tejun Heo   libata-pmp: imple...
786
  		/* PMP is reset, SErrors cannot be trusted, scan all */
1eca4365b   Tejun Heo   libata: beef up i...
787
  		ata_for_each_link(tlink, ap, EDGE) {
b558edddb   Tejun Heo   libata: kill ata_...
788
789
790
791
792
  			struct ata_eh_context *ehc = &tlink->eh_context;
  
  			ehc->i.probe_mask |= ATA_ALL_DEVICES;
  			ehc->i.action |= ATA_EH_RESET;
  		}
3af9a77af   Tejun Heo   libata-pmp: imple...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
  	}
  
  	/* If revalidation is requested, revalidate and reconfigure;
  	 * otherwise, do quick revalidation.
  	 */
  	if (ehc->i.action & ATA_EH_REVALIDATE)
  		rc = sata_pmp_revalidate(dev, ehc->classes[0]);
  	else
  		rc = sata_pmp_revalidate_quick(dev);
  
  	if (rc) {
  		tries--;
  
  		if (rc == -ENODEV) {
b558edddb   Tejun Heo   libata: kill ata_...
807
  			ehc->i.probe_mask |= ATA_ALL_DEVICES;
3af9a77af   Tejun Heo   libata-pmp: imple...
808
809
810
811
812
813
  			detach = 1;
  			/* give it just two more chances */
  			tries = min(tries, 2);
  		}
  
  		if (tries) {
3af9a77af   Tejun Heo   libata-pmp: imple...
814
815
  			/* consecutive revalidation failures? speed down */
  			if (reval_failed)
a07d499b4   Tejun Heo   libata: add @spd_...
816
  				sata_down_spd_limit(link, 0);
3af9a77af   Tejun Heo   libata-pmp: imple...
817
818
  			else
  				reval_failed = 1;
cf4806265   Tejun Heo   libata: prefer ha...
819
  			ehc->i.action |= ATA_EH_RESET;
3af9a77af   Tejun Heo   libata-pmp: imple...
820
821
  			goto retry;
  		} else {
a9a79dfec   Joe Perches   ata: Convert ata_...
822
823
824
825
  			ata_dev_err(dev,
  				    "failed to recover PMP after %d tries, giving up
  ",
  				    ATA_EH_PMP_TRIES);
3af9a77af   Tejun Heo   libata-pmp: imple...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
  			goto fail;
  		}
  	}
  
  	/* okay, PMP resurrected */
  	ehc->i.flags = 0;
  
  	DPRINTK("EXIT, rc=0
  ");
  	return 0;
  
   fail:
  	sata_pmp_detach(dev);
  	if (detach)
  		ata_eh_detach_dev(dev);
  	else
  		ata_dev_disable(dev);
  
  	DPRINTK("EXIT, rc=%d
  ", rc);
  	return rc;
  }
  
  static int sata_pmp_eh_handle_disabled_links(struct ata_port *ap)
  {
  	struct ata_link *link;
  	unsigned long flags;
  	int rc;
  
  	spin_lock_irqsave(ap->lock, flags);
1eca4365b   Tejun Heo   libata: beef up i...
856
  	ata_for_each_link(link, ap, EDGE) {
3af9a77af   Tejun Heo   libata-pmp: imple...
857
858
859
860
861
862
863
864
  		if (!(link->flags & ATA_LFLAG_DISABLED))
  			continue;
  
  		spin_unlock_irqrestore(ap->lock, flags);
  
  		/* Some PMPs require hardreset sequence to get
  		 * SError.N working.
  		 */
cf4806265   Tejun Heo   libata: prefer ha...
865
  		sata_link_hardreset(link, sata_deb_timing_normal,
341c2c958   Tejun Heo   libata: consisten...
866
867
  				ata_deadline(jiffies, ATA_TMOUT_INTERNAL_QUICK),
  				NULL, NULL);
3af9a77af   Tejun Heo   libata-pmp: imple...
868
869
870
871
  
  		/* unconditionally clear SError.N */
  		rc = sata_scr_write(link, SCR_ERROR, SERR_PHYRDY_CHG);
  		if (rc) {
a9a79dfec   Joe Perches   ata: Convert ata_...
872
873
874
875
  			ata_link_err(link,
  				     "failed to clear SError.N (errno=%d)
  ",
  				     rc);
3af9a77af   Tejun Heo   libata-pmp: imple...
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
  			return rc;
  		}
  
  		spin_lock_irqsave(ap->lock, flags);
  	}
  
  	spin_unlock_irqrestore(ap->lock, flags);
  
  	return 0;
  }
  
  static int sata_pmp_handle_link_fail(struct ata_link *link, int *link_tries)
  {
  	struct ata_port *ap = link->ap;
  	unsigned long flags;
  
  	if (link_tries[link->pmp] && --link_tries[link->pmp])
  		return 1;
  
  	/* disable this link */
  	if (!(link->flags & ATA_LFLAG_DISABLED)) {
a9a79dfec   Joe Perches   ata: Convert ata_...
897
  		ata_link_warn(link,
3af9a77af   Tejun Heo   libata-pmp: imple...
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
  			"failed to recover link after %d tries, disabling
  ",
  			ATA_EH_PMP_LINK_TRIES);
  
  		spin_lock_irqsave(ap->lock, flags);
  		link->flags |= ATA_LFLAG_DISABLED;
  		spin_unlock_irqrestore(ap->lock, flags);
  	}
  
  	ata_dev_disable(link->device);
  	link->eh_context.i.action = 0;
  
  	return 0;
  }
  
  /**
   *	sata_pmp_eh_recover - recover PMP-enabled port
   *	@ap: ATA port to recover
3af9a77af   Tejun Heo   libata-pmp: imple...
916
917
918
919
920
921
922
923
924
925
926
927
   *
   *	Drive EH recovery operation for PMP enabled port @ap.  This
   *	function recovers host and PMP ports with proper retrials and
   *	fallbacks.  Actual recovery operations are performed using
   *	ata_eh_recover() and sata_pmp_eh_recover_pmp().
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   *
   *	RETURNS:
   *	0 on success, -errno on failure.
   */
a1efdaba2   Tejun Heo   libata: make rese...
928
  static int sata_pmp_eh_recover(struct ata_port *ap)
3af9a77af   Tejun Heo   libata-pmp: imple...
929
  {
a1efdaba2   Tejun Heo   libata: make rese...
930
  	struct ata_port_operations *ops = ap->ops;
3af9a77af   Tejun Heo   libata-pmp: imple...
931
932
933
934
  	int pmp_tries, link_tries[SATA_PMP_MAX_PORTS];
  	struct ata_link *pmp_link = &ap->link;
  	struct ata_device *pmp_dev = pmp_link->device;
  	struct ata_eh_context *pmp_ehc = &pmp_link->eh_context;
f1bbfb90e   Tejun Heo   libata: make sure...
935
  	u32 *gscr = pmp_dev->gscr;
3af9a77af   Tejun Heo   libata-pmp: imple...
936
937
  	struct ata_link *link;
  	struct ata_device *dev;
b06ce3e51   Tejun Heo   libata: use ata_e...
938
  	unsigned int err_mask;
3af9a77af   Tejun Heo   libata-pmp: imple...
939
940
941
942
  	u32 gscr_error, sntf;
  	int cnt, rc;
  
  	pmp_tries = ATA_EH_PMP_TRIES;
1eca4365b   Tejun Heo   libata: beef up i...
943
  	ata_for_each_link(link, ap, EDGE)
3af9a77af   Tejun Heo   libata-pmp: imple...
944
945
946
947
  		link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
  
   retry:
  	/* PMP attached? */
071f44b1d   Tejun Heo   libata: implement...
948
  	if (!sata_pmp_attached(ap)) {
a1efdaba2   Tejun Heo   libata: make rese...
949
950
  		rc = ata_eh_recover(ap, ops->prereset, ops->softreset,
  				    ops->hardreset, ops->postreset, NULL);
3af9a77af   Tejun Heo   libata-pmp: imple...
951
  		if (rc) {
1eca4365b   Tejun Heo   libata: beef up i...
952
  			ata_for_each_dev(dev, &ap->link, ALL)
3af9a77af   Tejun Heo   libata-pmp: imple...
953
954
955
956
957
958
959
960
  				ata_dev_disable(dev);
  			return rc;
  		}
  
  		if (pmp_dev->class != ATA_DEV_PMP)
  			return 0;
  
  		/* new PMP online */
1eca4365b   Tejun Heo   libata: beef up i...
961
  		ata_for_each_link(link, ap, EDGE)
3af9a77af   Tejun Heo   libata-pmp: imple...
962
963
964
965
966
967
  			link_tries[link->pmp] = ATA_EH_PMP_LINK_TRIES;
  
  		/* fall through */
  	}
  
  	/* recover pmp */
a1efdaba2   Tejun Heo   libata: make rese...
968
969
  	rc = sata_pmp_eh_recover_pmp(ap, ops->prereset, ops->softreset,
  				     ops->hardreset, ops->postreset);
3af9a77af   Tejun Heo   libata-pmp: imple...
970
971
  	if (rc)
  		goto pmp_fail;
f1bbfb90e   Tejun Heo   libata: make sure...
972
973
974
975
976
977
978
979
980
  	/* PHY event notification can disturb reset and other recovery
  	 * operations.  Turn it off.
  	 */
  	if (gscr[SATA_PMP_GSCR_FEAT_EN] & SATA_PMP_FEAT_NOTIFY) {
  		gscr[SATA_PMP_GSCR_FEAT_EN] &= ~SATA_PMP_FEAT_NOTIFY;
  
  		err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
  					  gscr[SATA_PMP_GSCR_FEAT_EN]);
  		if (err_mask) {
a9a79dfec   Joe Perches   ata: Convert ata_...
981
  			ata_link_warn(pmp_link,
f1bbfb90e   Tejun Heo   libata: make sure...
982
983
984
985
986
987
  				"failed to disable NOTIFY (err_mask=0x%x)
  ",
  				err_mask);
  			goto pmp_fail;
  		}
  	}
3af9a77af   Tejun Heo   libata-pmp: imple...
988
989
990
991
992
993
  	/* handle disabled links */
  	rc = sata_pmp_eh_handle_disabled_links(ap);
  	if (rc)
  		goto pmp_fail;
  
  	/* recover links */
a1efdaba2   Tejun Heo   libata: make rese...
994
995
  	rc = ata_eh_recover(ap, ops->pmp_prereset, ops->pmp_softreset,
  			    ops->pmp_hardreset, ops->pmp_postreset, &link);
3af9a77af   Tejun Heo   libata-pmp: imple...
996
997
  	if (rc)
  		goto link_fail;
3af9a77af   Tejun Heo   libata-pmp: imple...
998
999
1000
1001
  	/* clear SNotification */
  	rc = sata_scr_read(&ap->link, SCR_NOTIFICATION, &sntf);
  	if (rc == 0)
  		sata_scr_write(&ap->link, SCR_NOTIFICATION, sntf);
6c8ea89ce   Tejun Heo   libata: implement...
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
  	/*
  	 * If LPM is active on any fan-out port, hotplug wouldn't
  	 * work.  Return w/ PHY event notification disabled.
  	 */
  	ata_for_each_link(link, ap, EDGE)
  		if (link->lpm_policy > ATA_LPM_MAX_POWER)
  			return 0;
  
  	/*
  	 * Connection status might have changed while resetting other
  	 * links, enable notification and check SATA_PMP_GSCR_ERROR
  	 * before returning.
  	 */
3af9a77af   Tejun Heo   libata-pmp: imple...
1015
1016
  	/* enable notification */
  	if (pmp_dev->flags & ATA_DFLAG_AN) {
f1bbfb90e   Tejun Heo   libata: make sure...
1017
  		gscr[SATA_PMP_GSCR_FEAT_EN] |= SATA_PMP_FEAT_NOTIFY;
3af9a77af   Tejun Heo   libata-pmp: imple...
1018

f1bbfb90e   Tejun Heo   libata: make sure...
1019
1020
  		err_mask = sata_pmp_write(pmp_link, SATA_PMP_GSCR_FEAT_EN,
  					  gscr[SATA_PMP_GSCR_FEAT_EN]);
b06ce3e51   Tejun Heo   libata: use ata_e...
1021
  		if (err_mask) {
a9a79dfec   Joe Perches   ata: Convert ata_...
1022
1023
1024
1025
  			ata_dev_err(pmp_dev,
  				    "failed to write PMP_FEAT_EN (Emask=0x%x)
  ",
  				    err_mask);
b06ce3e51   Tejun Heo   libata: use ata_e...
1026
  			rc = -EIO;
3af9a77af   Tejun Heo   libata-pmp: imple...
1027
1028
1029
1030
1031
  			goto pmp_fail;
  		}
  	}
  
  	/* check GSCR_ERROR */
b06ce3e51   Tejun Heo   libata: use ata_e...
1032
1033
  	err_mask = sata_pmp_read(pmp_link, SATA_PMP_GSCR_ERROR, &gscr_error);
  	if (err_mask) {
a9a79dfec   Joe Perches   ata: Convert ata_...
1034
1035
1036
1037
  		ata_dev_err(pmp_dev,
  			    "failed to read PMP_GSCR_ERROR (Emask=0x%x)
  ",
  			    err_mask);
b06ce3e51   Tejun Heo   libata: use ata_e...
1038
  		rc = -EIO;
3af9a77af   Tejun Heo   libata-pmp: imple...
1039
1040
1041
1042
  		goto pmp_fail;
  	}
  
  	cnt = 0;
1eca4365b   Tejun Heo   libata: beef up i...
1043
  	ata_for_each_link(link, ap, EDGE) {
3af9a77af   Tejun Heo   libata-pmp: imple...
1044
1045
1046
1047
1048
1049
1050
  		if (!(gscr_error & (1 << link->pmp)))
  			continue;
  
  		if (sata_pmp_handle_link_fail(link, link_tries)) {
  			ata_ehi_hotplugged(&link->eh_context.i);
  			cnt++;
  		} else {
a9a79dfec   Joe Perches   ata: Convert ata_...
1051
1052
1053
1054
1055
1056
  			ata_link_warn(link,
  				"PHY status changed but maxed out on retries, giving up
  ");
  			ata_link_warn(link,
  				"Manually issue scan to resume this link
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
1057
1058
1059
1060
  		}
  	}
  
  	if (cnt) {
a9a79dfec   Joe Perches   ata: Convert ata_...
1061
1062
1063
  		ata_port_info(ap,
  			"PMP SError.N set for some ports, repeating recovery
  ");
3af9a77af   Tejun Heo   libata-pmp: imple...
1064
1065
1066
1067
1068
1069
1070
  		goto retry;
  	}
  
  	return 0;
  
   link_fail:
  	if (sata_pmp_handle_link_fail(link, link_tries)) {
cf4806265   Tejun Heo   libata: prefer ha...
1071
  		pmp_ehc->i.action |= ATA_EH_RESET;
3af9a77af   Tejun Heo   libata-pmp: imple...
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
  		goto retry;
  	}
  
  	/* fall through */
   pmp_fail:
  	/* Control always ends up here after detaching PMP.  Shut up
  	 * and return if we're unloading.
  	 */
  	if (ap->pflags & ATA_PFLAG_UNLOADING)
  		return rc;
071f44b1d   Tejun Heo   libata: implement...
1082
  	if (!sata_pmp_attached(ap))
3af9a77af   Tejun Heo   libata-pmp: imple...
1083
1084
1085
  		goto retry;
  
  	if (--pmp_tries) {
cf4806265   Tejun Heo   libata: prefer ha...
1086
  		pmp_ehc->i.action |= ATA_EH_RESET;
3af9a77af   Tejun Heo   libata-pmp: imple...
1087
1088
  		goto retry;
  	}
a9a79dfec   Joe Perches   ata: Convert ata_...
1089
1090
1091
  	ata_port_err(ap, "failed to recover PMP after %d tries, giving up
  ",
  		     ATA_EH_PMP_TRIES);
3af9a77af   Tejun Heo   libata-pmp: imple...
1092
1093
1094
1095
1096
1097
1098
  	sata_pmp_detach(pmp_dev);
  	ata_dev_disable(pmp_dev);
  
  	return rc;
  }
  
  /**
a1efdaba2   Tejun Heo   libata: make rese...
1099
   *	sata_pmp_error_handler - do standard error handling for PMP-enabled host
3af9a77af   Tejun Heo   libata-pmp: imple...
1100
   *	@ap: host port to handle error for
3af9a77af   Tejun Heo   libata-pmp: imple...
1101
1102
1103
1104
1105
1106
1107
   *
   *	Perform standard error handling sequence for PMP-enabled host
   *	@ap.
   *
   *	LOCKING:
   *	Kernel thread context (may sleep).
   */
a1efdaba2   Tejun Heo   libata: make rese...
1108
  void sata_pmp_error_handler(struct ata_port *ap)
3af9a77af   Tejun Heo   libata-pmp: imple...
1109
1110
1111
  {
  	ata_eh_autopsy(ap);
  	ata_eh_report(ap);
a1efdaba2   Tejun Heo   libata: make rese...
1112
  	sata_pmp_eh_recover(ap);
3af9a77af   Tejun Heo   libata-pmp: imple...
1113
1114
  	ata_eh_finish(ap);
  }
48515f6c0   Tejun Heo   libata: separate ...
1115
1116
1117
1118
  
  EXPORT_SYMBOL_GPL(sata_pmp_port_ops);
  EXPORT_SYMBOL_GPL(sata_pmp_qc_defer_cmd_switch);
  EXPORT_SYMBOL_GPL(sata_pmp_error_handler);