aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/esas2r/esas2r_disc.c
diff options
context:
space:
mode:
authorBradley Grove <bgrove@attotech.com>2013-08-23 10:35:45 -0400
committerJames Bottomley <JBottomley@Parallels.com>2013-09-03 10:27:58 -0400
commit26780d9e12edf45c0b98315de272b1feff5a8e93 (patch)
tree2a5a00f53fa007277c9f92ef8c99b85d99d3b633 /drivers/scsi/esas2r/esas2r_disc.c
parent127be355285d14b483da0478a33302a680204144 (diff)
[SCSI] esas2r: ATTO Technology ExpressSAS 6G SAS/SATA RAID Adapter Driver
This is a new driver for ATTO Technology's ExpressSAS series of hardware RAID adapters. It supports the following adapters: - ExpressSAS R60F - ExpressSAS R680 - ExpressSAS R608 - ExpressSAS R644 Signed-off-by: Bradley Grove <bgrove@attotech.com> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi/esas2r/esas2r_disc.c')
-rw-r--r--drivers/scsi/esas2r/esas2r_disc.c1189
1 files changed, 1189 insertions, 0 deletions
diff --git a/drivers/scsi/esas2r/esas2r_disc.c b/drivers/scsi/esas2r/esas2r_disc.c
new file mode 100644
index 000000000000..dec6c334ce3e
--- /dev/null
+++ b/drivers/scsi/esas2r/esas2r_disc.c
@@ -0,0 +1,1189 @@
1/*
2 * linux/drivers/scsi/esas2r/esas2r_disc.c
3 * esas2r device discovery routines
4 *
5 * Copyright (c) 2001-2013 ATTO Technology, Inc.
6 * (mailto:linuxdrivers@attotech.com)
7 */
8/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
9/*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * NO WARRANTY
20 * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
21 * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
22 * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
23 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
24 * solely responsible for determining the appropriateness of using and
25 * distributing the Program and assumes all risks associated with its
26 * exercise of rights under this Agreement, including but not limited to
27 * the risks and costs of program errors, damage to or loss of data,
28 * programs or equipment, and unavailability or interruption of operations.
29 *
30 * DISCLAIMER OF LIABILITY
31 * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
32 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
34 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
35 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
36 * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
37 * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
38 *
39 * You should have received a copy of the GNU General Public License
40 * along with this program; if not, write to the Free Software
41 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42 */
43/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
44
45#include "esas2r.h"
46
47/* Miscellaneous internal discovery routines */
48static void esas2r_disc_abort(struct esas2r_adapter *a,
49 struct esas2r_request *rq);
50static bool esas2r_disc_continue(struct esas2r_adapter *a,
51 struct esas2r_request *rq);
52static void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a);
53static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr);
54static bool esas2r_disc_start_request(struct esas2r_adapter *a,
55 struct esas2r_request *rq);
56
57/* Internal discovery routines that process the states */
58static bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a,
59 struct esas2r_request *rq);
60static void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a,
61 struct esas2r_request *rq);
62static bool esas2r_disc_dev_add(struct esas2r_adapter *a,
63 struct esas2r_request *rq);
64static bool esas2r_disc_dev_remove(struct esas2r_adapter *a,
65 struct esas2r_request *rq);
66static bool esas2r_disc_part_info(struct esas2r_adapter *a,
67 struct esas2r_request *rq);
68static void esas2r_disc_part_info_cb(struct esas2r_adapter *a,
69 struct esas2r_request *rq);
70static bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a,
71 struct esas2r_request *rq);
72static void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a,
73 struct esas2r_request *rq);
74static bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a,
75 struct esas2r_request *rq);
76static void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a,
77 struct esas2r_request *rq);
78static bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a,
79 struct esas2r_request *rq);
80static void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a,
81 struct esas2r_request *rq);
82
83void esas2r_disc_initialize(struct esas2r_adapter *a)
84{
85 struct esas2r_sas_nvram *nvr = a->nvram;
86
87 esas2r_trace_enter();
88
89 esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
90 esas2r_lock_clear_flags(&a->flags2, AF2_DEV_SCAN);
91 esas2r_lock_clear_flags(&a->flags2, AF2_DEV_CNT_OK);
92
93 a->disc_start_time = jiffies_to_msecs(jiffies);
94 a->disc_wait_time = nvr->dev_wait_time * 1000;
95 a->disc_wait_cnt = nvr->dev_wait_count;
96
97 if (a->disc_wait_cnt > ESAS2R_MAX_TARGETS)
98 a->disc_wait_cnt = ESAS2R_MAX_TARGETS;
99
100 /*
101 * If we are doing chip reset or power management processing, always
102 * wait for devices. use the NVRAM device count if it is greater than
103 * previously discovered devices.
104 */
105
106 esas2r_hdebug("starting discovery...");
107
108 a->general_req.interrupt_cx = NULL;
109
110 if (a->flags & (AF_CHPRST_DETECTED | AF_POWER_MGT)) {
111 if (a->prev_dev_cnt == 0) {
112 /* Don't bother waiting if there is nothing to wait
113 * for.
114 */
115 a->disc_wait_time = 0;
116 } else {
117 /*
118 * Set the device wait count to what was previously
119 * found. We don't care if the user only configured
120 * a time because we know the exact count to wait for.
121 * There is no need to honor the user's wishes to
122 * always wait the full time.
123 */
124 a->disc_wait_cnt = a->prev_dev_cnt;
125
126 /*
127 * bump the minimum wait time to 15 seconds since the
128 * default is 3 (system boot or the boot driver usually
129 * buys us more time).
130 */
131 if (a->disc_wait_time < 15000)
132 a->disc_wait_time = 15000;
133 }
134 }
135
136 esas2r_trace("disc wait count: %d", a->disc_wait_cnt);
137 esas2r_trace("disc wait time: %d", a->disc_wait_time);
138
139 if (a->disc_wait_time == 0)
140 esas2r_disc_check_complete(a);
141
142 esas2r_trace_exit();
143}
144
145void esas2r_disc_start_waiting(struct esas2r_adapter *a)
146{
147 unsigned long flags;
148
149 spin_lock_irqsave(&a->mem_lock, flags);
150
151 if (a->disc_ctx.disc_evt)
152 esas2r_disc_start_port(a);
153
154 spin_unlock_irqrestore(&a->mem_lock, flags);
155}
156
157void esas2r_disc_check_for_work(struct esas2r_adapter *a)
158{
159 struct esas2r_request *rq = &a->general_req;
160
161 /* service any pending interrupts first */
162
163 esas2r_polled_interrupt(a);
164
165 /*
166 * now, interrupt processing may have queued up a discovery event. go
167 * see if we have one to start. we couldn't start it in the ISR since
168 * polled discovery would cause a deadlock.
169 */
170
171 esas2r_disc_start_waiting(a);
172
173 if (rq->interrupt_cx == NULL)
174 return;
175
176 if (rq->req_stat == RS_STARTED
177 && rq->timeout <= RQ_MAX_TIMEOUT) {
178 /* wait for the current discovery request to complete. */
179 esas2r_wait_request(a, rq);
180
181 if (rq->req_stat == RS_TIMEOUT) {
182 esas2r_disc_abort(a, rq);
183 esas2r_local_reset_adapter(a);
184 return;
185 }
186 }
187
188 if (rq->req_stat == RS_PENDING
189 || rq->req_stat == RS_STARTED)
190 return;
191
192 esas2r_disc_continue(a, rq);
193}
194
195void esas2r_disc_check_complete(struct esas2r_adapter *a)
196{
197 unsigned long flags;
198
199 esas2r_trace_enter();
200
201 /* check to see if we should be waiting for devices */
202 if (a->disc_wait_time) {
203 u32 currtime = jiffies_to_msecs(jiffies);
204 u32 time = currtime - a->disc_start_time;
205
206 /*
207 * Wait until the device wait time is exhausted or the device
208 * wait count is satisfied.
209 */
210 if (time < a->disc_wait_time
211 && (esas2r_targ_db_get_tgt_cnt(a) < a->disc_wait_cnt
212 || a->disc_wait_cnt == 0)) {
213 /* After three seconds of waiting, schedule a scan. */
214 if (time >= 3000
215 && !(esas2r_lock_set_flags(&a->flags2,
216 AF2_DEV_SCAN) &
217 ilog2(AF2_DEV_SCAN))) {
218 spin_lock_irqsave(&a->mem_lock, flags);
219 esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
220 spin_unlock_irqrestore(&a->mem_lock, flags);
221 }
222
223 esas2r_trace_exit();
224 return;
225 }
226
227 /*
228 * We are done waiting...we think. Adjust the wait time to
229 * consume events after the count is met.
230 */
231 if (!(esas2r_lock_set_flags(&a->flags2, AF2_DEV_CNT_OK)
232 & ilog2(AF2_DEV_CNT_OK)))
233 a->disc_wait_time = time + 3000;
234
235 /* If we haven't done a full scan yet, do it now. */
236 if (!(esas2r_lock_set_flags(&a->flags2,
237 AF2_DEV_SCAN) &
238 ilog2(AF2_DEV_SCAN))) {
239 spin_lock_irqsave(&a->mem_lock, flags);
240 esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
241 spin_unlock_irqrestore(&a->mem_lock, flags);
242
243 esas2r_trace_exit();
244 return;
245 }
246
247 /*
248 * Now, if there is still time left to consume events, continue
249 * waiting.
250 */
251 if (time < a->disc_wait_time) {
252 esas2r_trace_exit();
253 return;
254 }
255 } else {
256 if (!(esas2r_lock_set_flags(&a->flags2,
257 AF2_DEV_SCAN) &
258 ilog2(AF2_DEV_SCAN))) {
259 spin_lock_irqsave(&a->mem_lock, flags);
260 esas2r_disc_queue_event(a, DCDE_DEV_SCAN);
261 spin_unlock_irqrestore(&a->mem_lock, flags);
262 }
263 }
264
265 /* We want to stop waiting for devices. */
266 a->disc_wait_time = 0;
267
268 if ((a->flags & AF_DISC_POLLED)
269 && (a->flags & AF_DISC_IN_PROG)) {
270 /*
271 * Polled discovery is still pending so continue the active
272 * discovery until it is done. At that point, we will stop
273 * polled discovery and transition to interrupt driven
274 * discovery.
275 */
276 } else {
277 /*
278 * Done waiting for devices. Note that we get here immediately
279 * after deferred waiting completes because that is interrupt
280 * driven; i.e. There is no transition.
281 */
282 esas2r_disc_fix_curr_requests(a);
283 esas2r_lock_clear_flags(&a->flags, AF_DISC_PENDING);
284
285 /*
286 * We have deferred target state changes until now because we
287 * don't want to report any removals (due to the first arrival)
288 * until the device wait time expires.
289 */
290 esas2r_lock_set_flags(&a->flags, AF_PORT_CHANGE);
291 }
292
293 esas2r_trace_exit();
294}
295
296void esas2r_disc_queue_event(struct esas2r_adapter *a, u8 disc_evt)
297{
298 struct esas2r_disc_context *dc = &a->disc_ctx;
299
300 esas2r_trace_enter();
301
302 esas2r_trace("disc_event: %d", disc_evt);
303
304 /* Initialize the discovery context */
305 dc->disc_evt |= disc_evt;
306
307 /*
308 * Don't start discovery before or during polled discovery. if we did,
309 * we would have a deadlock if we are in the ISR already.
310 */
311 if (!(a->flags & (AF_CHPRST_PENDING | AF_DISC_POLLED)))
312 esas2r_disc_start_port(a);
313
314 esas2r_trace_exit();
315}
316
317bool esas2r_disc_start_port(struct esas2r_adapter *a)
318{
319 struct esas2r_request *rq = &a->general_req;
320 struct esas2r_disc_context *dc = &a->disc_ctx;
321 bool ret;
322
323 esas2r_trace_enter();
324
325 if (a->flags & AF_DISC_IN_PROG) {
326 esas2r_trace_exit();
327
328 return false;
329 }
330
331 /* If there is a discovery waiting, process it. */
332 if (dc->disc_evt) {
333 if ((a->flags & AF_DISC_POLLED)
334 && a->disc_wait_time == 0) {
335 /*
336 * We are doing polled discovery, but we no longer want
337 * to wait for devices. Stop polled discovery and
338 * transition to interrupt driven discovery.
339 */
340
341 esas2r_trace_exit();
342
343 return false;
344 }
345 } else {
346 /* Discovery is complete. */
347
348 esas2r_hdebug("disc done");
349
350 esas2r_lock_set_flags(&a->flags, AF_PORT_CHANGE);
351
352 esas2r_trace_exit();
353
354 return false;
355 }
356
357 /* Handle the discovery context */
358 esas2r_trace("disc_evt: %d", dc->disc_evt);
359 esas2r_lock_set_flags(&a->flags, AF_DISC_IN_PROG);
360 dc->flags = 0;
361
362 if (a->flags & AF_DISC_POLLED)
363 dc->flags |= DCF_POLLED;
364
365 rq->interrupt_cx = dc;
366 rq->req_stat = RS_SUCCESS;
367
368 /* Decode the event code */
369 if (dc->disc_evt & DCDE_DEV_SCAN) {
370 dc->disc_evt &= ~DCDE_DEV_SCAN;
371
372 dc->flags |= DCF_DEV_SCAN;
373 dc->state = DCS_BLOCK_DEV_SCAN;
374 } else if (dc->disc_evt & DCDE_DEV_CHANGE) {
375 dc->disc_evt &= ~DCDE_DEV_CHANGE;
376
377 dc->flags |= DCF_DEV_CHANGE;
378 dc->state = DCS_DEV_RMV;
379 }
380
381 /* Continue interrupt driven discovery */
382 if (!(a->flags & AF_DISC_POLLED))
383 ret = esas2r_disc_continue(a, rq);
384 else
385 ret = true;
386
387 esas2r_trace_exit();
388
389 return ret;
390}
391
392static bool esas2r_disc_continue(struct esas2r_adapter *a,
393 struct esas2r_request *rq)
394{
395 struct esas2r_disc_context *dc =
396 (struct esas2r_disc_context *)rq->interrupt_cx;
397 bool rslt;
398
399 /* Device discovery/removal */
400 while (dc->flags & (DCF_DEV_CHANGE | DCF_DEV_SCAN)) {
401 rslt = false;
402
403 switch (dc->state) {
404 case DCS_DEV_RMV:
405
406 rslt = esas2r_disc_dev_remove(a, rq);
407 break;
408
409 case DCS_DEV_ADD:
410
411 rslt = esas2r_disc_dev_add(a, rq);
412 break;
413
414 case DCS_BLOCK_DEV_SCAN:
415
416 rslt = esas2r_disc_block_dev_scan(a, rq);
417 break;
418
419 case DCS_RAID_GRP_INFO:
420
421 rslt = esas2r_disc_raid_grp_info(a, rq);
422 break;
423
424 case DCS_PART_INFO:
425
426 rslt = esas2r_disc_part_info(a, rq);
427 break;
428
429 case DCS_PT_DEV_INFO:
430
431 rslt = esas2r_disc_passthru_dev_info(a, rq);
432 break;
433 case DCS_PT_DEV_ADDR:
434
435 rslt = esas2r_disc_passthru_dev_addr(a, rq);
436 break;
437 case DCS_DISC_DONE:
438
439 dc->flags &= ~(DCF_DEV_CHANGE | DCF_DEV_SCAN);
440 break;
441
442 default:
443
444 esas2r_bugon();
445 dc->state = DCS_DISC_DONE;
446 break;
447 }
448
449 if (rslt)
450 return true;
451 }
452
453 /* Discovery is done...for now. */
454 rq->interrupt_cx = NULL;
455
456 if (!(a->flags & AF_DISC_PENDING))
457 esas2r_disc_fix_curr_requests(a);
458
459 esas2r_lock_clear_flags(&a->flags, AF_DISC_IN_PROG);
460
461 /* Start the next discovery. */
462 return esas2r_disc_start_port(a);
463}
464
465static bool esas2r_disc_start_request(struct esas2r_adapter *a,
466 struct esas2r_request *rq)
467{
468 unsigned long flags;
469
470 /* Set the timeout to a minimum value. */
471 if (rq->timeout < ESAS2R_DEFAULT_TMO)
472 rq->timeout = ESAS2R_DEFAULT_TMO;
473
474 /*
475 * Override the request type to distinguish discovery requests. If we
476 * end up deferring the request, esas2r_disc_local_start_request()
477 * will be called to restart it.
478 */
479 rq->req_type = RT_DISC_REQ;
480
481 spin_lock_irqsave(&a->queue_lock, flags);
482
483 if (!(a->flags & (AF_CHPRST_PENDING | AF_FLASHING)))
484 esas2r_disc_local_start_request(a, rq);
485 else
486 list_add_tail(&rq->req_list, &a->defer_list);
487
488 spin_unlock_irqrestore(&a->queue_lock, flags);
489
490 return true;
491}
492
493void esas2r_disc_local_start_request(struct esas2r_adapter *a,
494 struct esas2r_request *rq)
495{
496 esas2r_trace_enter();
497
498 list_add_tail(&rq->req_list, &a->active_list);
499
500 esas2r_start_vda_request(a, rq);
501
502 esas2r_trace_exit();
503
504 return;
505}
506
507static void esas2r_disc_abort(struct esas2r_adapter *a,
508 struct esas2r_request *rq)
509{
510 struct esas2r_disc_context *dc =
511 (struct esas2r_disc_context *)rq->interrupt_cx;
512
513 esas2r_trace_enter();
514
515 /* abort the current discovery */
516
517 dc->state = DCS_DISC_DONE;
518
519 esas2r_trace_exit();
520}
521
522static bool esas2r_disc_block_dev_scan(struct esas2r_adapter *a,
523 struct esas2r_request *rq)
524{
525 struct esas2r_disc_context *dc =
526 (struct esas2r_disc_context *)rq->interrupt_cx;
527 bool rslt;
528
529 esas2r_trace_enter();
530
531 esas2r_rq_init_request(rq, a);
532
533 esas2r_build_mgt_req(a,
534 rq,
535 VDAMGT_DEV_SCAN,
536 0,
537 0,
538 0,
539 NULL);
540
541 rq->comp_cb = esas2r_disc_block_dev_scan_cb;
542
543 rq->timeout = 30000;
544 rq->interrupt_cx = dc;
545
546 rslt = esas2r_disc_start_request(a, rq);
547
548 esas2r_trace_exit();
549
550 return rslt;
551}
552
553static void esas2r_disc_block_dev_scan_cb(struct esas2r_adapter *a,
554 struct esas2r_request *rq)
555{
556 struct esas2r_disc_context *dc =
557 (struct esas2r_disc_context *)rq->interrupt_cx;
558 unsigned long flags;
559
560 esas2r_trace_enter();
561
562 spin_lock_irqsave(&a->mem_lock, flags);
563
564 if (rq->req_stat == RS_SUCCESS)
565 dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
566
567 dc->state = DCS_RAID_GRP_INFO;
568 dc->raid_grp_ix = 0;
569
570 esas2r_rq_destroy_request(rq, a);
571
572 /* continue discovery if it's interrupt driven */
573
574 if (!(dc->flags & DCF_POLLED))
575 esas2r_disc_continue(a, rq);
576
577 spin_unlock_irqrestore(&a->mem_lock, flags);
578
579 esas2r_trace_exit();
580}
581
582static bool esas2r_disc_raid_grp_info(struct esas2r_adapter *a,
583 struct esas2r_request *rq)
584{
585 struct esas2r_disc_context *dc =
586 (struct esas2r_disc_context *)rq->interrupt_cx;
587 bool rslt;
588 struct atto_vda_grp_info *grpinfo;
589
590 esas2r_trace_enter();
591
592 esas2r_trace("raid_group_idx: %d", dc->raid_grp_ix);
593
594 if (dc->raid_grp_ix >= VDA_MAX_RAID_GROUPS) {
595 dc->state = DCS_DISC_DONE;
596
597 esas2r_trace_exit();
598
599 return false;
600 }
601
602 esas2r_rq_init_request(rq, a);
603
604 grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info;
605
606 memset(grpinfo, 0, sizeof(struct atto_vda_grp_info));
607
608 esas2r_build_mgt_req(a,
609 rq,
610 VDAMGT_GRP_INFO,
611 dc->scan_gen,
612 0,
613 sizeof(struct atto_vda_grp_info),
614 NULL);
615
616 grpinfo->grp_index = dc->raid_grp_ix;
617
618 rq->comp_cb = esas2r_disc_raid_grp_info_cb;
619
620 rq->interrupt_cx = dc;
621
622 rslt = esas2r_disc_start_request(a, rq);
623
624 esas2r_trace_exit();
625
626 return rslt;
627}
628
629static void esas2r_disc_raid_grp_info_cb(struct esas2r_adapter *a,
630 struct esas2r_request *rq)
631{
632 struct esas2r_disc_context *dc =
633 (struct esas2r_disc_context *)rq->interrupt_cx;
634 unsigned long flags;
635 struct atto_vda_grp_info *grpinfo;
636
637 esas2r_trace_enter();
638
639 spin_lock_irqsave(&a->mem_lock, flags);
640
641 if (rq->req_stat == RS_SCAN_GEN) {
642 dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
643 dc->raid_grp_ix = 0;
644 goto done;
645 }
646
647 if (rq->req_stat == RS_SUCCESS) {
648 grpinfo = &rq->vda_rsp_data->mgt_data.data.grp_info;
649
650 if (grpinfo->status != VDA_GRP_STAT_ONLINE
651 && grpinfo->status != VDA_GRP_STAT_DEGRADED) {
652 /* go to the next group. */
653
654 dc->raid_grp_ix++;
655 } else {
656 memcpy(&dc->raid_grp_name[0],
657 &grpinfo->grp_name[0],
658 sizeof(grpinfo->grp_name));
659
660 dc->interleave = le32_to_cpu(grpinfo->interleave);
661 dc->block_size = le32_to_cpu(grpinfo->block_size);
662
663 dc->state = DCS_PART_INFO;
664 dc->part_num = 0;
665 }
666 } else {
667 if (!(rq->req_stat == RS_GRP_INVALID)) {
668 esas2r_log(ESAS2R_LOG_WARN,
669 "A request for RAID group info failed - "
670 "returned with %x",
671 rq->req_stat);
672 }
673
674 dc->dev_ix = 0;
675 dc->state = DCS_PT_DEV_INFO;
676 }
677
678done:
679
680 esas2r_rq_destroy_request(rq, a);
681
682 /* continue discovery if it's interrupt driven */
683
684 if (!(dc->flags & DCF_POLLED))
685 esas2r_disc_continue(a, rq);
686
687 spin_unlock_irqrestore(&a->mem_lock, flags);
688
689 esas2r_trace_exit();
690}
691
692static bool esas2r_disc_part_info(struct esas2r_adapter *a,
693 struct esas2r_request *rq)
694{
695 struct esas2r_disc_context *dc =
696 (struct esas2r_disc_context *)rq->interrupt_cx;
697 bool rslt;
698 struct atto_vdapart_info *partinfo;
699
700 esas2r_trace_enter();
701
702 esas2r_trace("part_num: %d", dc->part_num);
703
704 if (dc->part_num >= VDA_MAX_PARTITIONS) {
705 dc->state = DCS_RAID_GRP_INFO;
706 dc->raid_grp_ix++;
707
708 esas2r_trace_exit();
709
710 return false;
711 }
712
713 esas2r_rq_init_request(rq, a);
714
715 partinfo = &rq->vda_rsp_data->mgt_data.data.part_info;
716
717 memset(partinfo, 0, sizeof(struct atto_vdapart_info));
718
719 esas2r_build_mgt_req(a,
720 rq,
721 VDAMGT_PART_INFO,
722 dc->scan_gen,
723 0,
724 sizeof(struct atto_vdapart_info),
725 NULL);
726
727 partinfo->part_no = dc->part_num;
728
729 memcpy(&partinfo->grp_name[0],
730 &dc->raid_grp_name[0],
731 sizeof(partinfo->grp_name));
732
733 rq->comp_cb = esas2r_disc_part_info_cb;
734
735 rq->interrupt_cx = dc;
736
737 rslt = esas2r_disc_start_request(a, rq);
738
739 esas2r_trace_exit();
740
741 return rslt;
742}
743
744static void esas2r_disc_part_info_cb(struct esas2r_adapter *a,
745 struct esas2r_request *rq)
746{
747 struct esas2r_disc_context *dc =
748 (struct esas2r_disc_context *)rq->interrupt_cx;
749 unsigned long flags;
750 struct atto_vdapart_info *partinfo;
751
752 esas2r_trace_enter();
753
754 spin_lock_irqsave(&a->mem_lock, flags);
755
756 if (rq->req_stat == RS_SCAN_GEN) {
757 dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
758 dc->raid_grp_ix = 0;
759 dc->state = DCS_RAID_GRP_INFO;
760 } else if (rq->req_stat == RS_SUCCESS) {
761 partinfo = &rq->vda_rsp_data->mgt_data.data.part_info;
762
763 dc->part_num = partinfo->part_no;
764
765 dc->curr_virt_id = le16_to_cpu(partinfo->target_id);
766
767 esas2r_targ_db_add_raid(a, dc);
768
769 dc->part_num++;
770 } else {
771 if (!(rq->req_stat == RS_PART_LAST)) {
772 esas2r_log(ESAS2R_LOG_WARN,
773 "A request for RAID group partition info "
774 "failed - status:%d", rq->req_stat);
775 }
776
777 dc->state = DCS_RAID_GRP_INFO;
778 dc->raid_grp_ix++;
779 }
780
781 esas2r_rq_destroy_request(rq, a);
782
783 /* continue discovery if it's interrupt driven */
784
785 if (!(dc->flags & DCF_POLLED))
786 esas2r_disc_continue(a, rq);
787
788 spin_unlock_irqrestore(&a->mem_lock, flags);
789
790 esas2r_trace_exit();
791}
792
793static bool esas2r_disc_passthru_dev_info(struct esas2r_adapter *a,
794 struct esas2r_request *rq)
795{
796 struct esas2r_disc_context *dc =
797 (struct esas2r_disc_context *)rq->interrupt_cx;
798 bool rslt;
799 struct atto_vda_devinfo *devinfo;
800
801 esas2r_trace_enter();
802
803 esas2r_trace("dev_ix: %d", dc->dev_ix);
804
805 esas2r_rq_init_request(rq, a);
806
807 devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info;
808
809 memset(devinfo, 0, sizeof(struct atto_vda_devinfo));
810
811 esas2r_build_mgt_req(a,
812 rq,
813 VDAMGT_DEV_PT_INFO,
814 dc->scan_gen,
815 dc->dev_ix,
816 sizeof(struct atto_vda_devinfo),
817 NULL);
818
819 rq->comp_cb = esas2r_disc_passthru_dev_info_cb;
820
821 rq->interrupt_cx = dc;
822
823 rslt = esas2r_disc_start_request(a, rq);
824
825 esas2r_trace_exit();
826
827 return rslt;
828}
829
830static void esas2r_disc_passthru_dev_info_cb(struct esas2r_adapter *a,
831 struct esas2r_request *rq)
832{
833 struct esas2r_disc_context *dc =
834 (struct esas2r_disc_context *)rq->interrupt_cx;
835 unsigned long flags;
836 struct atto_vda_devinfo *devinfo;
837
838 esas2r_trace_enter();
839
840 spin_lock_irqsave(&a->mem_lock, flags);
841
842 if (rq->req_stat == RS_SCAN_GEN) {
843 dc->scan_gen = rq->func_rsp.mgt_rsp.scan_generation;
844 dc->dev_ix = 0;
845 dc->state = DCS_PT_DEV_INFO;
846 } else if (rq->req_stat == RS_SUCCESS) {
847 devinfo = &rq->vda_rsp_data->mgt_data.data.dev_info;
848
849 dc->dev_ix = le16_to_cpu(rq->func_rsp.mgt_rsp.dev_index);
850
851 dc->curr_virt_id = le16_to_cpu(devinfo->target_id);
852
853 if (le16_to_cpu(devinfo->features) & VDADEVFEAT_PHYS_ID) {
854 dc->curr_phys_id =
855 le16_to_cpu(devinfo->phys_target_id);
856 dc->dev_addr_type = ATTO_GDA_AT_PORT;
857 dc->state = DCS_PT_DEV_ADDR;
858
859 esas2r_trace("curr_virt_id: %d", dc->curr_virt_id);
860 esas2r_trace("curr_phys_id: %d", dc->curr_phys_id);
861 } else {
862 dc->dev_ix++;
863 }
864 } else {
865 if (!(rq->req_stat == RS_DEV_INVALID)) {
866 esas2r_log(ESAS2R_LOG_WARN,
867 "A request for device information failed - "
868 "status:%d", rq->req_stat);
869 }
870
871 dc->state = DCS_DISC_DONE;
872 }
873
874 esas2r_rq_destroy_request(rq, a);
875
876 /* continue discovery if it's interrupt driven */
877
878 if (!(dc->flags & DCF_POLLED))
879 esas2r_disc_continue(a, rq);
880
881 spin_unlock_irqrestore(&a->mem_lock, flags);
882
883 esas2r_trace_exit();
884}
885
886static bool esas2r_disc_passthru_dev_addr(struct esas2r_adapter *a,
887 struct esas2r_request *rq)
888{
889 struct esas2r_disc_context *dc =
890 (struct esas2r_disc_context *)rq->interrupt_cx;
891 bool rslt;
892 struct atto_ioctl *hi;
893 struct esas2r_sg_context sgc;
894
895 esas2r_trace_enter();
896
897 esas2r_rq_init_request(rq, a);
898
899 /* format the request. */
900
901 sgc.cur_offset = NULL;
902 sgc.get_phys_addr = (PGETPHYSADDR)esas2r_disc_get_phys_addr;
903 sgc.length = offsetof(struct atto_ioctl, data)
904 + sizeof(struct atto_hba_get_device_address);
905
906 esas2r_sgc_init(&sgc, a, rq, rq->vrq->ioctl.sge);
907
908 esas2r_build_ioctl_req(a, rq, sgc.length, VDA_IOCTL_HBA);
909
910 if (!esas2r_build_sg_list(a, rq, &sgc)) {
911 esas2r_rq_destroy_request(rq, a);
912
913 esas2r_trace_exit();
914
915 return false;
916 }
917
918 rq->comp_cb = esas2r_disc_passthru_dev_addr_cb;
919
920 rq->interrupt_cx = dc;
921
922 /* format the IOCTL data. */
923
924 hi = (struct atto_ioctl *)a->disc_buffer;
925
926 memset(a->disc_buffer, 0, ESAS2R_DISC_BUF_LEN);
927
928 hi->version = ATTO_VER_GET_DEV_ADDR0;
929 hi->function = ATTO_FUNC_GET_DEV_ADDR;
930 hi->flags = HBAF_TUNNEL;
931
932 hi->data.get_dev_addr.target_id = le32_to_cpu(dc->curr_phys_id);
933 hi->data.get_dev_addr.addr_type = dc->dev_addr_type;
934
935 /* start it up. */
936
937 rslt = esas2r_disc_start_request(a, rq);
938
939 esas2r_trace_exit();
940
941 return rslt;
942}
943
944static void esas2r_disc_passthru_dev_addr_cb(struct esas2r_adapter *a,
945 struct esas2r_request *rq)
946{
947 struct esas2r_disc_context *dc =
948 (struct esas2r_disc_context *)rq->interrupt_cx;
949 struct esas2r_target *t = NULL;
950 unsigned long flags;
951 struct atto_ioctl *hi;
952 u16 addrlen;
953
954 esas2r_trace_enter();
955
956 spin_lock_irqsave(&a->mem_lock, flags);
957
958 hi = (struct atto_ioctl *)a->disc_buffer;
959
960 if (rq->req_stat == RS_SUCCESS
961 && hi->status == ATTO_STS_SUCCESS) {
962 addrlen = le16_to_cpu(hi->data.get_dev_addr.addr_len);
963
964 if (dc->dev_addr_type == ATTO_GDA_AT_PORT) {
965 if (addrlen == sizeof(u64))
966 memcpy(&dc->sas_addr,
967 &hi->data.get_dev_addr.address[0],
968 addrlen);
969 else
970 memset(&dc->sas_addr, 0, sizeof(dc->sas_addr));
971
972 /* Get the unique identifier. */
973 dc->dev_addr_type = ATTO_GDA_AT_UNIQUE;
974
975 goto next_dev_addr;
976 } else {
977 /* Add the pass through target. */
978 if (HIBYTE(addrlen) == 0) {
979 t = esas2r_targ_db_add_pthru(a,
980 dc,
981 &hi->data.
982 get_dev_addr.
983 address[0],
984 (u8)hi->data.
985 get_dev_addr.
986 addr_len);
987
988 if (t)
989 memcpy(&t->sas_addr, &dc->sas_addr,
990 sizeof(t->sas_addr));
991 } else {
992 /* getting the back end data failed */
993
994 esas2r_log(ESAS2R_LOG_WARN,
995 "an error occurred retrieving the "
996 "back end data (%s:%d)",
997 __func__,
998 __LINE__);
999 }
1000 }
1001 } else {
1002 /* getting the back end data failed */
1003
1004 esas2r_log(ESAS2R_LOG_WARN,
1005 "an error occurred retrieving the back end data - "
1006 "rq->req_stat:%d hi->status:%d",
1007 rq->req_stat, hi->status);
1008 }
1009
1010 /* proceed to the next device. */
1011
1012 if (dc->flags & DCF_DEV_SCAN) {
1013 dc->dev_ix++;
1014 dc->state = DCS_PT_DEV_INFO;
1015 } else if (dc->flags & DCF_DEV_CHANGE) {
1016 dc->curr_targ++;
1017 dc->state = DCS_DEV_ADD;
1018 } else {
1019 esas2r_bugon();
1020 }
1021
1022next_dev_addr:
1023 esas2r_rq_destroy_request(rq, a);
1024
1025 /* continue discovery if it's interrupt driven */
1026
1027 if (!(dc->flags & DCF_POLLED))
1028 esas2r_disc_continue(a, rq);
1029
1030 spin_unlock_irqrestore(&a->mem_lock, flags);
1031
1032 esas2r_trace_exit();
1033}
1034
1035static u32 esas2r_disc_get_phys_addr(struct esas2r_sg_context *sgc, u64 *addr)
1036{
1037 struct esas2r_adapter *a = sgc->adapter;
1038
1039 if (sgc->length > ESAS2R_DISC_BUF_LEN)
1040 esas2r_bugon();
1041
1042 *addr = a->uncached_phys
1043 + (u64)((u8 *)a->disc_buffer - a->uncached);
1044
1045 return sgc->length;
1046}
1047
1048static bool esas2r_disc_dev_remove(struct esas2r_adapter *a,
1049 struct esas2r_request *rq)
1050{
1051 struct esas2r_disc_context *dc =
1052 (struct esas2r_disc_context *)rq->interrupt_cx;
1053 struct esas2r_target *t;
1054 struct esas2r_target *t2;
1055
1056 esas2r_trace_enter();
1057
1058 /* process removals. */
1059
1060 for (t = a->targetdb; t < a->targetdb_end; t++) {
1061 if (t->new_target_state != TS_NOT_PRESENT)
1062 continue;
1063
1064 t->new_target_state = TS_INVALID;
1065
1066 /* remove the right target! */
1067
1068 t2 =
1069 esas2r_targ_db_find_by_virt_id(a,
1070 esas2r_targ_get_id(t,
1071 a));
1072
1073 if (t2)
1074 esas2r_targ_db_remove(a, t2);
1075 }
1076
1077 /* removals complete. process arrivals. */
1078
1079 dc->state = DCS_DEV_ADD;
1080 dc->curr_targ = a->targetdb;
1081
1082 esas2r_trace_exit();
1083
1084 return false;
1085}
1086
1087static bool esas2r_disc_dev_add(struct esas2r_adapter *a,
1088 struct esas2r_request *rq)
1089{
1090 struct esas2r_disc_context *dc =
1091 (struct esas2r_disc_context *)rq->interrupt_cx;
1092 struct esas2r_target *t = dc->curr_targ;
1093
1094 if (t >= a->targetdb_end) {
1095 /* done processing state changes. */
1096
1097 dc->state = DCS_DISC_DONE;
1098 } else if (t->new_target_state == TS_PRESENT) {
1099 struct atto_vda_ae_lu *luevt = &t->lu_event;
1100
1101 esas2r_trace_enter();
1102
1103 /* clear this now in case more events come in. */
1104
1105 t->new_target_state = TS_INVALID;
1106
1107 /* setup the discovery context for adding this device. */
1108
1109 dc->curr_virt_id = esas2r_targ_get_id(t, a);
1110
1111 if ((luevt->hdr.bylength >= offsetof(struct atto_vda_ae_lu, id)
1112 + sizeof(struct atto_vda_ae_lu_tgt_lun_raid))
1113 && !(luevt->dwevent & VDAAE_LU_PASSTHROUGH)) {
1114 dc->block_size = luevt->id.tgtlun_raid.dwblock_size;
1115 dc->interleave = luevt->id.tgtlun_raid.dwinterleave;
1116 } else {
1117 dc->block_size = 0;
1118 dc->interleave = 0;
1119 }
1120
1121 /* determine the device type being added. */
1122
1123 if (luevt->dwevent & VDAAE_LU_PASSTHROUGH) {
1124 if (luevt->dwevent & VDAAE_LU_PHYS_ID) {
1125 dc->state = DCS_PT_DEV_ADDR;
1126 dc->dev_addr_type = ATTO_GDA_AT_PORT;
1127 dc->curr_phys_id = luevt->wphys_target_id;
1128 } else {
1129 esas2r_log(ESAS2R_LOG_WARN,
1130 "luevt->dwevent does not have the "
1131 "VDAAE_LU_PHYS_ID bit set (%s:%d)",
1132 __func__, __LINE__);
1133 }
1134 } else {
1135 dc->raid_grp_name[0] = 0;
1136
1137 esas2r_targ_db_add_raid(a, dc);
1138 }
1139
1140 esas2r_trace("curr_virt_id: %d", dc->curr_virt_id);
1141 esas2r_trace("curr_phys_id: %d", dc->curr_phys_id);
1142 esas2r_trace("dwevent: %d", luevt->dwevent);
1143
1144 esas2r_trace_exit();
1145 }
1146
1147 if (dc->state == DCS_DEV_ADD) {
1148 /* go to the next device. */
1149
1150 dc->curr_targ++;
1151 }
1152
1153 return false;
1154}
1155
1156/*
1157 * When discovery is done, find all requests on defer queue and
1158 * test if they need to be modified. If a target is no longer present
1159 * then complete the request with RS_SEL. Otherwise, update the
1160 * target_id since after a hibernate it can be a different value.
1161 * VDA does not make passthrough target IDs persistent.
1162 */
1163static void esas2r_disc_fix_curr_requests(struct esas2r_adapter *a)
1164{
1165 unsigned long flags;
1166 struct esas2r_target *t;
1167 struct esas2r_request *rq;
1168 struct list_head *element;
1169
1170 /* update virt_targ_id in any outstanding esas2r_requests */
1171
1172 spin_lock_irqsave(&a->queue_lock, flags);
1173
1174 list_for_each(element, &a->defer_list) {
1175 rq = list_entry(element, struct esas2r_request, req_list);
1176 if (rq->vrq->scsi.function == VDA_FUNC_SCSI) {
1177 t = a->targetdb + rq->target_id;
1178
1179 if (t->target_state == TS_PRESENT)
1180 rq->vrq->scsi.target_id = le16_to_cpu(
1181 t->virt_targ_id);
1182 else
1183 rq->req_stat = RS_SEL;
1184 }
1185
1186 }
1187
1188 spin_unlock_irqrestore(&a->queue_lock, flags);
1189}