-
Notifications
You must be signed in to change notification settings - Fork 7
/
ipr.c
9242 lines (8035 loc) · 256 KB
/
ipr.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
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
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
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
560
561
562
563
564
565
566
567
568
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
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
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
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
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
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
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
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* ipr.c -- driver for IBM Power Linux RAID adapters
*
* Written By: Brian King <brking@us.ibm.com>, IBM Corporation
*
* Copyright (C) 2003, 2004 IBM Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* Notes:
*
* This driver is used to control the following SCSI adapters:
*
* IBM iSeries: 5702, 5703, 2780, 5709, 570A, 570B
*
* IBM pSeries: PCI-X Dual Channel Ultra 320 SCSI RAID Adapter
* PCI-X Dual Channel Ultra 320 SCSI Adapter
* PCI-X Dual Channel Ultra 320 SCSI RAID Enablement Card
* Embedded SCSI adapter on p615 and p655 systems
*
* Supported Hardware Features:
* - Ultra 320 SCSI controller
* - PCI-X host interface
* - Embedded PowerPC RISC Processor and Hardware XOR DMA Engine
* - Non-Volatile Write Cache
* - Supports attachment of non-RAID disks, tape, and optical devices
* - RAID Levels 0, 5, 10
* - Hot spare
* - Background Parity Checking
* - Background Data Scrubbing
* - Ability to increase the capacity of an existing RAID 5 disk array
* by adding disks
*
* Driver Features:
* - Tagged command queuing
* - Adapter microcode download
* - PCI hot plug
* - SCSI device hot plug
*
*/
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/libata.h>
#include <linux/hdreg.h>
#include <linux/reboot.h>
#include <linux/stringify.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_cmnd.h>
#include "ipr.h"
/*
* Global Data
*/
static LIST_HEAD(ipr_ioa_head);
static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
static unsigned int ipr_max_speed = 1;
static int ipr_testmode = 0;
static unsigned int ipr_fastfail = 0;
static unsigned int ipr_transop_timeout = 0;
static unsigned int ipr_debug = 0;
static unsigned int ipr_max_devs = IPR_DEFAULT_SIS64_DEVS;
static unsigned int ipr_dual_ioa_raid = 1;
static DEFINE_SPINLOCK(ipr_driver_lock);
/* This table describes the differences between DMA controller chips */
static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
{ /* Gemstone, Citrine, Obsidian, and Obsidian-E */
.mailbox = 0x0042C,
.cache_line_size = 0x20,
{
.set_interrupt_mask_reg = 0x0022C,
.clr_interrupt_mask_reg = 0x00230,
.clr_interrupt_mask_reg32 = 0x00230,
.sense_interrupt_mask_reg = 0x0022C,
.sense_interrupt_mask_reg32 = 0x0022C,
.clr_interrupt_reg = 0x00228,
.clr_interrupt_reg32 = 0x00228,
.sense_interrupt_reg = 0x00224,
.sense_interrupt_reg32 = 0x00224,
.ioarrin_reg = 0x00404,
.sense_uproc_interrupt_reg = 0x00214,
.sense_uproc_interrupt_reg32 = 0x00214,
.set_uproc_interrupt_reg = 0x00214,
.set_uproc_interrupt_reg32 = 0x00214,
.clr_uproc_interrupt_reg = 0x00218,
.clr_uproc_interrupt_reg32 = 0x00218
}
},
{ /* Snipe and Scamp */
.mailbox = 0x0052C,
.cache_line_size = 0x20,
{
.set_interrupt_mask_reg = 0x00288,
.clr_interrupt_mask_reg = 0x0028C,
.clr_interrupt_mask_reg32 = 0x0028C,
.sense_interrupt_mask_reg = 0x00288,
.sense_interrupt_mask_reg32 = 0x00288,
.clr_interrupt_reg = 0x00284,
.clr_interrupt_reg32 = 0x00284,
.sense_interrupt_reg = 0x00280,
.sense_interrupt_reg32 = 0x00280,
.ioarrin_reg = 0x00504,
.sense_uproc_interrupt_reg = 0x00290,
.sense_uproc_interrupt_reg32 = 0x00290,
.set_uproc_interrupt_reg = 0x00290,
.set_uproc_interrupt_reg32 = 0x00290,
.clr_uproc_interrupt_reg = 0x00294,
.clr_uproc_interrupt_reg32 = 0x00294
}
},
{ /* CRoC */
.mailbox = 0x00044,
.cache_line_size = 0x20,
{
.set_interrupt_mask_reg = 0x00010,
.clr_interrupt_mask_reg = 0x00018,
.clr_interrupt_mask_reg32 = 0x0001C,
.sense_interrupt_mask_reg = 0x00010,
.sense_interrupt_mask_reg32 = 0x00014,
.clr_interrupt_reg = 0x00008,
.clr_interrupt_reg32 = 0x0000C,
.sense_interrupt_reg = 0x00000,
.sense_interrupt_reg32 = 0x00004,
.ioarrin_reg = 0x00070,
.sense_uproc_interrupt_reg = 0x00020,
.sense_uproc_interrupt_reg32 = 0x00024,
.set_uproc_interrupt_reg = 0x00020,
.set_uproc_interrupt_reg32 = 0x00024,
.clr_uproc_interrupt_reg = 0x00028,
.clr_uproc_interrupt_reg32 = 0x0002C,
.init_feedback_reg = 0x0005C,
.dump_addr_reg = 0x00064,
.dump_data_reg = 0x00068,
.endian_swap_reg = 0x00084
}
},
};
static const struct ipr_chip_t ipr_chip[] = {
{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E, IPR_USE_MSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[0] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, IPR_USE_LSI, IPR_SIS32, IPR_PCI_CFG, &ipr_chip_cfg[1] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_FPGA_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] },
{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CROC_ASIC_E2, IPR_USE_MSI, IPR_SIS64, IPR_MMIO, &ipr_chip_cfg[2] }
};
static int ipr_max_bus_speeds [] = {
IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE
};
MODULE_AUTHOR("Brian King <brking@us.ibm.com>");
MODULE_DESCRIPTION("IBM Power RAID SCSI Adapter Driver");
module_param_named(max_speed, ipr_max_speed, uint, 0);
MODULE_PARM_DESC(max_speed, "Maximum bus speed (0-2). Default: 1=U160. Speeds: 0=80 MB/s, 1=U160, 2=U320");
module_param_named(log_level, ipr_log_level, uint, 0);
MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver");
module_param_named(testmode, ipr_testmode, int, 0);
MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations");
module_param_named(fastfail, ipr_fastfail, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries");
module_param_named(transop_timeout, ipr_transop_timeout, int, 0);
MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)");
module_param_named(debug, ipr_debug, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Enable device driver debugging logging. Set to 1 to enable. (default: 0)");
module_param_named(dual_ioa_raid, ipr_dual_ioa_raid, int, 0);
MODULE_PARM_DESC(dual_ioa_raid, "Enable dual adapter RAID support. Set to 1 to enable. (default: 1)");
module_param_named(max_devs, ipr_max_devs, int, 0);
MODULE_PARM_DESC(max_devs, "Specify the maximum number of physical devices. "
"[Default=" __stringify(IPR_DEFAULT_SIS64_DEVS) "]");
MODULE_LICENSE("GPL");
MODULE_VERSION(IPR_DRIVER_VERSION);
/* A constant array of IOASCs/URCs/Error Messages */
static const
struct ipr_error_table_t ipr_error_table[] = {
{0x00000000, 1, IPR_DEFAULT_LOG_LEVEL,
"8155: An unknown error was received"},
{0x00330000, 0, 0,
"Soft underlength error"},
{0x005A0000, 0, 0,
"Command to be cancelled not found"},
{0x00808000, 0, 0,
"Qualified success"},
{0x01080000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFFE: Soft device bus error recovered by the IOA"},
{0x01088100, 0, IPR_DEFAULT_LOG_LEVEL,
"4101: Soft device bus fabric error"},
{0x01100100, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFC: Logical block guard error recovered by the device"},
{0x01100300, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFC: Logical block reference tag error recovered by the device"},
{0x01108300, 0, IPR_DEFAULT_LOG_LEVEL,
"4171: Recovered scatter list tag / sequence number error"},
{0x01109000, 0, IPR_DEFAULT_LOG_LEVEL,
"FF3D: Recovered logical block CRC error on IOA to Host transfer"},
{0x01109200, 0, IPR_DEFAULT_LOG_LEVEL,
"4171: Recovered logical block sequence number error on IOA to Host transfer"},
{0x0110A000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFD: Recovered logical block reference tag error detected by the IOA"},
{0x0110A100, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFD: Logical block guard error recovered by the IOA"},
{0x01170600, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF9: Device sector reassign successful"},
{0x01170900, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF7: Media error recovered by device rewrite procedures"},
{0x01180200, 0, IPR_DEFAULT_LOG_LEVEL,
"7001: IOA sector reassignment successful"},
{0x01180500, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF9: Soft media error. Sector reassignment recommended"},
{0x01180600, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF7: Media error recovered by IOA rewrite procedures"},
{0x01418000, 0, IPR_DEFAULT_LOG_LEVEL,
"FF3D: Soft PCI bus error recovered by the IOA"},
{0x01440000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device hardware error recovered by the IOA"},
{0x01448100, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device hardware error recovered by the device"},
{0x01448200, 1, IPR_DEFAULT_LOG_LEVEL,
"FF3D: Soft IOA error recovered by the IOA"},
{0x01448300, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFA: Undefined device response recovered by the IOA"},
{0x014A0000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Device bus error, message or command phase"},
{0x014A8000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFE: Task Management Function failed"},
{0x015D0000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF6: Failure prediction threshold exceeded"},
{0x015D9200, 0, IPR_DEFAULT_LOG_LEVEL,
"8009: Impending cache battery pack failure"},
{0x02040400, 0, 0,
"34FF: Disk device format in progress"},
{0x02048000, 0, IPR_DEFAULT_LOG_LEVEL,
"9070: IOA requested reset"},
{0x023F0000, 0, 0,
"Synchronization required"},
{0x024E0000, 0, 0,
"No ready, IOA shutdown"},
{0x025A0000, 0, 0,
"Not ready, IOA has been shutdown"},
{0x02670100, 0, IPR_DEFAULT_LOG_LEVEL,
"3020: Storage subsystem configuration error"},
{0x03110B00, 0, 0,
"FFF5: Medium error, data unreadable, recommend reassign"},
{0x03110C00, 0, 0,
"7000: Medium error, data unreadable, do not reassign"},
{0x03310000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF3: Disk media format bad"},
{0x04050000, 0, IPR_DEFAULT_LOG_LEVEL,
"3002: Addressed device failed to respond to selection"},
{0x04080000, 1, IPR_DEFAULT_LOG_LEVEL,
"3100: Device bus error"},
{0x04080100, 0, IPR_DEFAULT_LOG_LEVEL,
"3109: IOA timed out a device command"},
{0x04088000, 0, 0,
"3120: SCSI bus is not operational"},
{0x04088100, 0, IPR_DEFAULT_LOG_LEVEL,
"4100: Hard device bus fabric error"},
{0x04100100, 0, IPR_DEFAULT_LOG_LEVEL,
"310C: Logical block guard error detected by the device"},
{0x04100300, 0, IPR_DEFAULT_LOG_LEVEL,
"310C: Logical block reference tag error detected by the device"},
{0x04108300, 1, IPR_DEFAULT_LOG_LEVEL,
"4170: Scatter list tag / sequence number error"},
{0x04109000, 1, IPR_DEFAULT_LOG_LEVEL,
"8150: Logical block CRC error on IOA to Host transfer"},
{0x04109200, 1, IPR_DEFAULT_LOG_LEVEL,
"4170: Logical block sequence number error on IOA to Host transfer"},
{0x0410A000, 0, IPR_DEFAULT_LOG_LEVEL,
"310D: Logical block reference tag error detected by the IOA"},
{0x0410A100, 0, IPR_DEFAULT_LOG_LEVEL,
"310D: Logical block guard error detected by the IOA"},
{0x04118000, 0, IPR_DEFAULT_LOG_LEVEL,
"9000: IOA reserved area data check"},
{0x04118100, 0, IPR_DEFAULT_LOG_LEVEL,
"9001: IOA reserved area invalid data pattern"},
{0x04118200, 0, IPR_DEFAULT_LOG_LEVEL,
"9002: IOA reserved area LRC error"},
{0x04118300, 1, IPR_DEFAULT_LOG_LEVEL,
"Hardware Error, IOA metadata access error"},
{0x04320000, 0, IPR_DEFAULT_LOG_LEVEL,
"102E: Out of alternate sectors for disk storage"},
{0x04330000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Data transfer underlength error"},
{0x04338000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Data transfer overlength error"},
{0x043E0100, 0, IPR_DEFAULT_LOG_LEVEL,
"3400: Logical unit failure"},
{0x04408500, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Device microcode is corrupt"},
{0x04418000, 1, IPR_DEFAULT_LOG_LEVEL,
"8150: PCI bus error"},
{0x04430000, 1, 0,
"Unsupported device bus message received"},
{0x04440000, 1, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Disk device problem"},
{0x04448200, 1, IPR_DEFAULT_LOG_LEVEL,
"8150: Permanent IOA failure"},
{0x04448300, 0, IPR_DEFAULT_LOG_LEVEL,
"3010: Disk device returned wrong response to IOA"},
{0x04448400, 0, IPR_DEFAULT_LOG_LEVEL,
"8151: IOA microcode error"},
{0x04448500, 0, 0,
"Device bus status error"},
{0x04448600, 0, IPR_DEFAULT_LOG_LEVEL,
"8157: IOA error requiring IOA reset to recover"},
{0x04448700, 0, 0,
"ATA device status error"},
{0x04490000, 0, 0,
"Message reject received from the device"},
{0x04449200, 0, IPR_DEFAULT_LOG_LEVEL,
"8008: A permanent cache battery pack failure occurred"},
{0x0444A000, 0, IPR_DEFAULT_LOG_LEVEL,
"9090: Disk unit has been modified after the last known status"},
{0x0444A200, 0, IPR_DEFAULT_LOG_LEVEL,
"9081: IOA detected device error"},
{0x0444A300, 0, IPR_DEFAULT_LOG_LEVEL,
"9082: IOA detected device error"},
{0x044A0000, 1, IPR_DEFAULT_LOG_LEVEL,
"3110: Device bus error, message or command phase"},
{0x044A8000, 1, IPR_DEFAULT_LOG_LEVEL,
"3110: SAS Command / Task Management Function failed"},
{0x04670400, 0, IPR_DEFAULT_LOG_LEVEL,
"9091: Incorrect hardware configuration change has been detected"},
{0x04678000, 0, IPR_DEFAULT_LOG_LEVEL,
"9073: Invalid multi-adapter configuration"},
{0x04678100, 0, IPR_DEFAULT_LOG_LEVEL,
"4010: Incorrect connection between cascaded expanders"},
{0x04678200, 0, IPR_DEFAULT_LOG_LEVEL,
"4020: Connections exceed IOA design limits"},
{0x04678300, 0, IPR_DEFAULT_LOG_LEVEL,
"4030: Incorrect multipath connection"},
{0x04679000, 0, IPR_DEFAULT_LOG_LEVEL,
"4110: Unsupported enclosure function"},
{0x046E0000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFF4: Command to logical unit failed"},
{0x05240000, 1, 0,
"Illegal request, invalid request type or request packet"},
{0x05250000, 0, 0,
"Illegal request, invalid resource handle"},
{0x05258000, 0, 0,
"Illegal request, commands not allowed to this device"},
{0x05258100, 0, 0,
"Illegal request, command not allowed to a secondary adapter"},
{0x05258200, 0, 0,
"Illegal request, command not allowed to a non-optimized resource"},
{0x05260000, 0, 0,
"Illegal request, invalid field in parameter list"},
{0x05260100, 0, 0,
"Illegal request, parameter not supported"},
{0x05260200, 0, 0,
"Illegal request, parameter value invalid"},
{0x052C0000, 0, 0,
"Illegal request, command sequence error"},
{0x052C8000, 1, 0,
"Illegal request, dual adapter support not enabled"},
{0x06040500, 0, IPR_DEFAULT_LOG_LEVEL,
"9031: Array protection temporarily suspended, protection resuming"},
{0x06040600, 0, IPR_DEFAULT_LOG_LEVEL,
"9040: Array protection temporarily suspended, protection resuming"},
{0x06288000, 0, IPR_DEFAULT_LOG_LEVEL,
"3140: Device bus not ready to ready transition"},
{0x06290000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFB: SCSI bus was reset"},
{0x06290500, 0, 0,
"FFFE: SCSI bus transition to single ended"},
{0x06290600, 0, 0,
"FFFE: SCSI bus transition to LVD"},
{0x06298000, 0, IPR_DEFAULT_LOG_LEVEL,
"FFFB: SCSI bus was reset by another initiator"},
{0x063F0300, 0, IPR_DEFAULT_LOG_LEVEL,
"3029: A device replacement has occurred"},
{0x064C8000, 0, IPR_DEFAULT_LOG_LEVEL,
"9051: IOA cache data exists for a missing or failed device"},
{0x064C8100, 0, IPR_DEFAULT_LOG_LEVEL,
"9055: Auxiliary cache IOA contains cache data needed by the primary IOA"},
{0x06670100, 0, IPR_DEFAULT_LOG_LEVEL,
"9025: Disk unit is not supported at its physical location"},
{0x06670600, 0, IPR_DEFAULT_LOG_LEVEL,
"3020: IOA detected a SCSI bus configuration error"},
{0x06678000, 0, IPR_DEFAULT_LOG_LEVEL,
"3150: SCSI bus configuration error"},
{0x06678100, 0, IPR_DEFAULT_LOG_LEVEL,
"9074: Asymmetric advanced function disk configuration"},
{0x06678300, 0, IPR_DEFAULT_LOG_LEVEL,
"4040: Incomplete multipath connection between IOA and enclosure"},
{0x06678400, 0, IPR_DEFAULT_LOG_LEVEL,
"4041: Incomplete multipath connection between enclosure and device"},
{0x06678500, 0, IPR_DEFAULT_LOG_LEVEL,
"9075: Incomplete multipath connection between IOA and remote IOA"},
{0x06678600, 0, IPR_DEFAULT_LOG_LEVEL,
"9076: Configuration error, missing remote IOA"},
{0x06679100, 0, IPR_DEFAULT_LOG_LEVEL,
"4050: Enclosure does not support a required multipath function"},
{0x06690000, 0, IPR_DEFAULT_LOG_LEVEL,
"4070: Logically bad block written on device"},
{0x06690200, 0, IPR_DEFAULT_LOG_LEVEL,
"9041: Array protection temporarily suspended"},
{0x06698200, 0, IPR_DEFAULT_LOG_LEVEL,
"9042: Corrupt array parity detected on specified device"},
{0x066B0200, 0, IPR_DEFAULT_LOG_LEVEL,
"9030: Array no longer protected due to missing or failed disk unit"},
{0x066B8000, 0, IPR_DEFAULT_LOG_LEVEL,
"9071: Link operational transition"},
{0x066B8100, 0, IPR_DEFAULT_LOG_LEVEL,
"9072: Link not operational transition"},
{0x066B8200, 0, IPR_DEFAULT_LOG_LEVEL,
"9032: Array exposed but still protected"},
{0x066B8300, 0, IPR_DEFAULT_LOG_LEVEL + 1,
"70DD: Device forced failed by disrupt device command"},
{0x066B9100, 0, IPR_DEFAULT_LOG_LEVEL,
"4061: Multipath redundancy level got better"},
{0x066B9200, 0, IPR_DEFAULT_LOG_LEVEL,
"4060: Multipath redundancy level got worse"},
{0x07270000, 0, 0,
"Failure due to other device"},
{0x07278000, 0, IPR_DEFAULT_LOG_LEVEL,
"9008: IOA does not support functions expected by devices"},
{0x07278100, 0, IPR_DEFAULT_LOG_LEVEL,
"9010: Cache data associated with attached devices cannot be found"},
{0x07278200, 0, IPR_DEFAULT_LOG_LEVEL,
"9011: Cache data belongs to devices other than those attached"},
{0x07278400, 0, IPR_DEFAULT_LOG_LEVEL,
"9020: Array missing 2 or more devices with only 1 device present"},
{0x07278500, 0, IPR_DEFAULT_LOG_LEVEL,
"9021: Array missing 2 or more devices with 2 or more devices present"},
{0x07278600, 0, IPR_DEFAULT_LOG_LEVEL,
"9022: Exposed array is missing a required device"},
{0x07278700, 0, IPR_DEFAULT_LOG_LEVEL,
"9023: Array member(s) not at required physical locations"},
{0x07278800, 0, IPR_DEFAULT_LOG_LEVEL,
"9024: Array not functional due to present hardware configuration"},
{0x07278900, 0, IPR_DEFAULT_LOG_LEVEL,
"9026: Array not functional due to present hardware configuration"},
{0x07278A00, 0, IPR_DEFAULT_LOG_LEVEL,
"9027: Array is missing a device and parity is out of sync"},
{0x07278B00, 0, IPR_DEFAULT_LOG_LEVEL,
"9028: Maximum number of arrays already exist"},
{0x07278C00, 0, IPR_DEFAULT_LOG_LEVEL,
"9050: Required cache data cannot be located for a disk unit"},
{0x07278D00, 0, IPR_DEFAULT_LOG_LEVEL,
"9052: Cache data exists for a device that has been modified"},
{0x07278F00, 0, IPR_DEFAULT_LOG_LEVEL,
"9054: IOA resources not available due to previous problems"},
{0x07279100, 0, IPR_DEFAULT_LOG_LEVEL,
"9092: Disk unit requires initialization before use"},
{0x07279200, 0, IPR_DEFAULT_LOG_LEVEL,
"9029: Incorrect hardware configuration change has been detected"},
{0x07279600, 0, IPR_DEFAULT_LOG_LEVEL,
"9060: One or more disk pairs are missing from an array"},
{0x07279700, 0, IPR_DEFAULT_LOG_LEVEL,
"9061: One or more disks are missing from an array"},
{0x07279800, 0, IPR_DEFAULT_LOG_LEVEL,
"9062: One or more disks are missing from an array"},
{0x07279900, 0, IPR_DEFAULT_LOG_LEVEL,
"9063: Maximum number of functional arrays has been exceeded"},
{0x0B260000, 0, 0,
"Aborted command, invalid descriptor"},
{0x0B5A0000, 0, 0,
"Command terminated by host"}
};
static const struct ipr_ses_table_entry ipr_ses_table[] = {
{ "2104-DL1 ", "XXXXXXXXXXXXXXXX", 80 },
{ "2104-TL1 ", "XXXXXXXXXXXXXXXX", 80 },
{ "HSBP07M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 7 slot */
{ "HSBP05M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 5 slot */
{ "HSBP05M S U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Bowtie */
{ "HSBP06E ASU2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* MartinFenning */
{ "2104-DU3 ", "XXXXXXXXXXXXXXXX", 160 },
{ "2104-TU3 ", "XXXXXXXXXXXXXXXX", 160 },
{ "HSBP04C RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 },
{ "HSBP06E RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 },
{ "St V1S2 ", "XXXXXXXXXXXXXXXX", 160 },
{ "HSBPD4M PU3SCSI", "XXXXXXX*XXXXXXXX", 160 },
{ "VSBPD1H U3SCSI", "XXXXXXX*XXXXXXXX", 160 }
};
/*
* Function Prototypes
*/
static int ipr_reset_alert(struct ipr_cmnd *);
static void ipr_process_ccn(struct ipr_cmnd *);
static void ipr_process_error(struct ipr_cmnd *);
static void ipr_reset_ioa_job(struct ipr_cmnd *);
static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *,
enum ipr_shutdown_type);
#ifdef CONFIG_SCSI_IPR_TRACE
/**
* ipr_trc_hook - Add a trace entry to the driver trace
* @ipr_cmd: ipr command struct
* @type: trace type
* @add_data: additional data
*
* Return value:
* none
**/
static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
u8 type, u32 add_data)
{
struct ipr_trace_entry *trace_entry;
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
trace_entry = &ioa_cfg->trace[ioa_cfg->trace_index++];
trace_entry->time = jiffies;
trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
trace_entry->type = type;
if (ipr_cmd->ioa_cfg->sis64)
trace_entry->ata_op_code = ipr_cmd->i.ata_ioadl.regs.command;
else
trace_entry->ata_op_code = ipr_cmd->ioarcb.u.add_data.u.regs.command;
trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff;
trace_entry->res_handle = ipr_cmd->ioarcb.res_handle;
trace_entry->u.add_data = add_data;
}
#else
#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0)
#endif
/**
* ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse
* @ipr_cmd: ipr command struct
*
* Return value:
* none
**/
static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
struct ipr_ioasa *ioasa = &ipr_cmd->s.ioasa;
struct ipr_ioasa64 *ioasa64 = &ipr_cmd->s.ioasa64;
dma_addr_t dma_addr = ipr_cmd->dma_addr;
memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
ioarcb->data_transfer_length = 0;
ioarcb->read_data_transfer_length = 0;
ioarcb->ioadl_len = 0;
ioarcb->read_ioadl_len = 0;
if (ipr_cmd->ioa_cfg->sis64) {
ioarcb->u.sis64_addr_data.data_ioadl_addr =
cpu_to_be64(dma_addr + offsetof(struct ipr_cmnd, i.ioadl64));
ioasa64->u.gata.status = 0;
} else {
ioarcb->write_ioadl_addr =
cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, i.ioadl));
ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
ioasa->u.gata.status = 0;
}
ioasa->hdr.ioasc = 0;
ioasa->hdr.residual_data_len = 0;
ipr_cmd->scsi_cmd = NULL;
ipr_cmd->qc = NULL;
ipr_cmd->sense_buffer[0] = 0;
ipr_cmd->dma_use_sg = 0;
}
/**
* ipr_init_ipr_cmnd - Initialize an IPR Cmnd block
* @ipr_cmd: ipr command struct
*
* Return value:
* none
**/
static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
{
ipr_reinit_ipr_cmnd(ipr_cmd);
ipr_cmd->u.scratch = 0;
ipr_cmd->sibling = NULL;
init_timer(&ipr_cmd->timer);
}
/**
* ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block
* @ioa_cfg: ioa config struct
*
* Return value:
* pointer to ipr command struct
**/
static
struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg)
{
struct ipr_cmnd *ipr_cmd;
ipr_cmd = list_entry(ioa_cfg->free_q.next, struct ipr_cmnd, queue);
list_del(&ipr_cmd->queue);
ipr_init_ipr_cmnd(ipr_cmd);
return ipr_cmd;
}
/**
* ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts
* @ioa_cfg: ioa config struct
* @clr_ints: interrupts to clear
*
* This function masks all interrupts on the adapter, then clears the
* interrupts specified in the mask
*
* Return value:
* none
**/
static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg,
u32 clr_ints)
{
volatile u32 int_reg;
/* Stop new interrupts */
ioa_cfg->allow_interrupts = 0;
/* Set interrupt mask to stop all new interrupts */
if (ioa_cfg->sis64)
writeq(~0, ioa_cfg->regs.set_interrupt_mask_reg);
else
writel(~0, ioa_cfg->regs.set_interrupt_mask_reg);
/* Clear any pending interrupts */
if (ioa_cfg->sis64)
writel(~0, ioa_cfg->regs.clr_interrupt_reg);
writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg32);
int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
}
/**
* ipr_save_pcix_cmd_reg - Save PCI-X command register
* @ioa_cfg: ioa config struct
*
* Return value:
* 0 on success / -EIO on failure
**/
static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
{
int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);
if (pcix_cmd_reg == 0)
return 0;
if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
&ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {
dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n");
return -EIO;
}
ioa_cfg->saved_pcix_cmd_reg |= PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO;
return 0;
}
/**
* ipr_set_pcix_cmd_reg - Setup PCI-X command register
* @ioa_cfg: ioa config struct
*
* Return value:
* 0 on success / -EIO on failure
**/
static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
{
int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);
if (pcix_cmd_reg) {
if (pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {
dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n");
return -EIO;
}
}
return 0;
}
/**
* ipr_sata_eh_done - done function for aborted SATA commands
* @ipr_cmd: ipr command struct
*
* This function is invoked for ops generated to SATA
* devices which are being aborted.
*
* Return value:
* none
**/
static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
struct ata_queued_cmd *qc = ipr_cmd->qc;
struct ipr_sata_port *sata_port = qc->ap->private_data;
qc->err_mask |= AC_ERR_OTHER;
sata_port->ioasa.status |= ATA_BUSY;
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
ata_qc_complete(qc);
}
/**
* ipr_scsi_eh_done - mid-layer done function for aborted ops
* @ipr_cmd: ipr command struct
*
* This function is invoked by the interrupt handler for
* ops generated by the SCSI mid-layer which are being aborted.
*
* Return value:
* none
**/
static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
scsi_cmd->result |= (DID_ERROR << 16);
scsi_dma_unmap(ipr_cmd->scsi_cmd);
scsi_cmd->scsi_done(scsi_cmd);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
}
/**
* ipr_fail_all_ops - Fails all outstanding ops.
* @ioa_cfg: ioa config struct
*
* This function fails all outstanding ops.
*
* Return value:
* none
**/
static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg)
{
struct ipr_cmnd *ipr_cmd, *temp;
ENTER;
list_for_each_entry_safe(ipr_cmd, temp, &ioa_cfg->pending_q, queue) {
list_del(&ipr_cmd->queue);
ipr_cmd->s.ioasa.hdr.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET);
ipr_cmd->s.ioasa.hdr.ilid = cpu_to_be32(IPR_DRIVER_ILID);
if (ipr_cmd->scsi_cmd)
ipr_cmd->done = ipr_scsi_eh_done;
else if (ipr_cmd->qc)
ipr_cmd->done = ipr_sata_eh_done;
ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET);
del_timer(&ipr_cmd->timer);
ipr_cmd->done(ipr_cmd);
}
LEAVE;
}
/**
* ipr_send_command - Send driver initiated requests.
* @ipr_cmd: ipr command struct
*
* This function sends a command to the adapter using the correct write call.
* In the case of sis64, calculate the ioarcb size required. Then or in the
* appropriate bits.
*
* Return value:
* none
**/
static void ipr_send_command(struct ipr_cmnd *ipr_cmd)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
dma_addr_t send_dma_addr = ipr_cmd->dma_addr;
if (ioa_cfg->sis64) {
/* The default size is 256 bytes */
send_dma_addr |= 0x1;
/* If the number of ioadls * size of ioadl > 128 bytes,
then use a 512 byte ioarcb */
if (ipr_cmd->dma_use_sg * sizeof(struct ipr_ioadl64_desc) > 128 )
send_dma_addr |= 0x4;
writeq(send_dma_addr, ioa_cfg->regs.ioarrin_reg);
} else
writel(send_dma_addr, ioa_cfg->regs.ioarrin_reg);
}
/**
* ipr_do_req - Send driver initiated requests.
* @ipr_cmd: ipr command struct
* @done: done function
* @timeout_func: timeout function
* @timeout: timeout value
*
* This function sends the specified command to the adapter with the
* timeout given. The done function is invoked on command completion.
*
* Return value:
* none
**/
static void ipr_do_req(struct ipr_cmnd *ipr_cmd,
void (*done) (struct ipr_cmnd *),
void (*timeout_func) (struct ipr_cmnd *), u32 timeout)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
ipr_cmd->done = done;
ipr_cmd->timer.data = (unsigned long) ipr_cmd;
ipr_cmd->timer.expires = jiffies + timeout;
ipr_cmd->timer.function = (void (*)(unsigned long))timeout_func;
add_timer(&ipr_cmd->timer);
ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0);
mb();
ipr_send_command(ipr_cmd);
}
/**
* ipr_internal_cmd_done - Op done function for an internally generated op.
* @ipr_cmd: ipr command struct
*
* This function is the op done function for an internally generated,
* blocking op. It simply wakes the sleeping thread.
*
* Return value:
* none
**/
static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd)
{
if (ipr_cmd->sibling)
ipr_cmd->sibling = NULL;
else
complete(&ipr_cmd->completion);
}
/**
* ipr_init_ioadl - initialize the ioadl for the correct SIS type
* @ipr_cmd: ipr command struct
* @dma_addr: dma address
* @len: transfer length
* @flags: ioadl flag value
*
* This function initializes an ioadl in the case where there is only a single
* descriptor.
*
* Return value:
* nothing
**/
static void ipr_init_ioadl(struct ipr_cmnd *ipr_cmd, dma_addr_t dma_addr,
u32 len, int flags)
{
struct ipr_ioadl_desc *ioadl = ipr_cmd->i.ioadl;
struct ipr_ioadl64_desc *ioadl64 = ipr_cmd->i.ioadl64;
ipr_cmd->dma_use_sg = 1;
if (ipr_cmd->ioa_cfg->sis64) {
ioadl64->flags = cpu_to_be32(flags);
ioadl64->data_len = cpu_to_be32(len);
ioadl64->address = cpu_to_be64(dma_addr);
ipr_cmd->ioarcb.ioadl_len =
cpu_to_be32(sizeof(struct ipr_ioadl64_desc));
ipr_cmd->ioarcb.data_transfer_length = cpu_to_be32(len);
} else {
ioadl->flags_and_data_len = cpu_to_be32(flags | len);
ioadl->address = cpu_to_be32(dma_addr);
if (flags == IPR_IOADL_FLAGS_READ_LAST) {
ipr_cmd->ioarcb.read_ioadl_len =
cpu_to_be32(sizeof(struct ipr_ioadl_desc));
ipr_cmd->ioarcb.read_data_transfer_length = cpu_to_be32(len);
} else {
ipr_cmd->ioarcb.ioadl_len =
cpu_to_be32(sizeof(struct ipr_ioadl_desc));
ipr_cmd->ioarcb.data_transfer_length = cpu_to_be32(len);
}
}
}
/**
* ipr_send_blocking_cmd - Send command and sleep on its completion.
* @ipr_cmd: ipr command struct
* @timeout_func: function to invoke if command times out
* @timeout: timeout
*
* Return value:
* none
**/
static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd,
void (*timeout_func) (struct ipr_cmnd *ipr_cmd),
u32 timeout)
{
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
init_completion(&ipr_cmd->completion);
ipr_do_req(ipr_cmd, ipr_internal_cmd_done, timeout_func, timeout);
spin_unlock_irq(ioa_cfg->host->host_lock);
wait_for_completion(&ipr_cmd->completion);
spin_lock_irq(ioa_cfg->host->host_lock);
}
/**
* ipr_send_hcam - Send an HCAM to the adapter.
* @ioa_cfg: ioa config struct
* @type: HCAM type
* @hostrcb: hostrcb struct
*
* This function will send a Host Controlled Async command to the adapter.
* If HCAMs are currently not allowed to be issued to the adapter, it will
* place the hostrcb on the free queue.
*
* Return value:
* none
**/
static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type,
struct ipr_hostrcb *hostrcb)
{
struct ipr_cmnd *ipr_cmd;
struct ipr_ioarcb *ioarcb;
if (ioa_cfg->allow_cmds) {
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_pending_q);
ipr_cmd->u.hostrcb = hostrcb;
ioarcb = &ipr_cmd->ioarcb;
ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
ioarcb->cmd_pkt.request_type = IPR_RQTYPE_HCAM;
ioarcb->cmd_pkt.cdb[0] = IPR_HOST_CONTROLLED_ASYNC;
ioarcb->cmd_pkt.cdb[1] = type;
ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff;
ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff;
ipr_init_ioadl(ipr_cmd, hostrcb->hostrcb_dma,
sizeof(hostrcb->hcam), IPR_IOADL_FLAGS_READ_LAST);
if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE)
ipr_cmd->done = ipr_process_ccn;
else
ipr_cmd->done = ipr_process_error;
ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR);
mb();
ipr_send_command(ipr_cmd);
} else {
list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
}
}
/**
* ipr_update_ata_class - Update the ata class in the resource entry
* @res: resource entry struct
* @proto: cfgte device bus protocol value
*
* Return value:
* none
**/