GNU Linux-libre 5.10.219-gnu1
[releases.git] / drivers / scsi / gdth_proc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* gdth_proc.c 
3  * $Id: gdth_proc.c,v 1.43 2006/01/11 16:15:00 achim Exp $
4  */
5
6 #include <linux/completion.h>
7 #include <linux/slab.h>
8
9 int gdth_set_info(struct Scsi_Host *host, char *buffer, int length)
10 {
11     gdth_ha_str *ha = shost_priv(host);
12     int ret_val = -EINVAL;
13
14     TRACE2(("gdth_set_info() ha %d\n",ha->hanum,));
15
16     if (length >= 4) {
17         if (strncmp(buffer,"gdth",4) == 0) {
18             buffer += 5;
19             length -= 5;
20             ret_val = gdth_set_asc_info(host, buffer, length, ha);
21         }
22     }
23
24     return ret_val;
25 }
26          
27 static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
28                         int length, gdth_ha_str *ha)
29 {
30     int orig_length, drive, wb_mode;
31     int i, found;
32     gdth_cmd_str    gdtcmd;
33     gdth_cpar_str   *pcpar;
34
35     char            cmnd[MAX_COMMAND_SIZE];
36     memset(cmnd, 0xff, 12);
37     memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
38
39     TRACE2(("gdth_set_asc_info() ha %d\n",ha->hanum));
40     orig_length = length + 5;
41     drive = -1;
42     wb_mode = 0;
43     found = FALSE;
44
45     if (length >= 5 && strncmp(buffer,"flush",5)==0) {
46         buffer += 6;
47         length -= 6;
48         if (length && *buffer>='0' && *buffer<='9') {
49             drive = (int)(*buffer-'0');
50             ++buffer; --length;
51             if (length && *buffer>='0' && *buffer<='9') {
52                 drive = drive*10 + (int)(*buffer-'0');
53                 ++buffer; --length;
54             }
55             printk("GDT: Flushing host drive %d .. ",drive);
56         } else {
57             printk("GDT: Flushing all host drives .. ");
58         }
59         for (i = 0; i < MAX_HDRIVES; ++i) {
60             if (ha->hdr[i].present) {
61                 if (drive != -1 && i != drive)
62                     continue;
63                 found = TRUE;
64                 gdtcmd.Service = CACHESERVICE;
65                 gdtcmd.OpCode = GDT_FLUSH;
66                 if (ha->cache_feat & GDT_64BIT) {
67                     gdtcmd.u.cache64.DeviceNo = i;
68                     gdtcmd.u.cache64.BlockNo = 1;
69                 } else {
70                     gdtcmd.u.cache.DeviceNo = i;
71                     gdtcmd.u.cache.BlockNo = 1;
72                 }
73
74                 gdth_execute(host, &gdtcmd, cmnd, 30, NULL);
75             }
76         }
77         if (!found)
78             printk("\nNo host drive found !\n");
79         else
80             printk("Done.\n");
81         return(orig_length);
82     }
83
84     if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
85         buffer += 8;
86         length -= 8;
87         printk("GDT: Disabling write back permanently .. ");
88         wb_mode = 1;
89     } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
90         buffer += 7;
91         length -= 7;
92         printk("GDT: Enabling write back permanently .. ");
93         wb_mode = 2;
94     } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
95         buffer += 7;
96         length -= 7;
97         printk("GDT: Disabling write back commands .. ");
98         if (ha->cache_feat & GDT_WR_THROUGH) {
99             gdth_write_through = TRUE;
100             printk("Done.\n");
101         } else {
102             printk("Not supported !\n");
103         }
104         return(orig_length);
105     } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
106         buffer += 6;
107         length -= 6;
108         printk("GDT: Enabling write back commands .. ");
109         gdth_write_through = FALSE;
110         printk("Done.\n");
111         return(orig_length);
112     }
113
114     if (wb_mode) {
115         unsigned long flags;
116
117         BUILD_BUG_ON(sizeof(gdth_cpar_str) > GDTH_SCRATCH);
118
119         spin_lock_irqsave(&ha->smp_lock, flags);
120         if (ha->scratch_busy) {
121             spin_unlock_irqrestore(&ha->smp_lock, flags);
122             return -EBUSY;
123         }
124         ha->scratch_busy = TRUE;
125         spin_unlock_irqrestore(&ha->smp_lock, flags);
126
127         pcpar = (gdth_cpar_str *)ha->pscratch;
128         memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
129         gdtcmd.Service = CACHESERVICE;
130         gdtcmd.OpCode = GDT_IOCTL;
131         gdtcmd.u.ioctl.p_param = ha->scratch_phys;
132         gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
133         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
134         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
135         pcpar->write_back = wb_mode==1 ? 0:1;
136
137         gdth_execute(host, &gdtcmd, cmnd, 30, NULL);
138
139         spin_lock_irqsave(&ha->smp_lock, flags);
140         ha->scratch_busy = FALSE;
141         spin_unlock_irqrestore(&ha->smp_lock, flags);
142
143         printk("Done.\n");
144         return(orig_length);
145     }
146
147     printk("GDT: Unknown command: %s  Length: %d\n",buffer,length);
148     return(-EINVAL);
149 }
150
151 int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
152 {
153     gdth_ha_str *ha = shost_priv(host);
154     int hlen;
155     int id, i, j, k, sec, flag;
156     int no_mdrv = 0, drv_no, is_mirr;
157     u32 cnt;
158     dma_addr_t paddr;
159     int rc = -ENOMEM;
160
161     gdth_cmd_str *gdtcmd;
162     gdth_evt_str *estr;
163     char hrec[277];
164
165     char *buf;
166     gdth_dskstat_str *pds;
167     gdth_diskinfo_str *pdi;
168     gdth_arrayinf_str *pai;
169     gdth_defcnt_str *pdef;
170     gdth_cdrinfo_str *pcdi;
171     gdth_hget_str *phg;
172     char cmnd[MAX_COMMAND_SIZE];
173
174     gdtcmd = kmalloc(sizeof(*gdtcmd), GFP_KERNEL);
175     estr = kmalloc(sizeof(*estr), GFP_KERNEL);
176     if (!gdtcmd || !estr)
177         goto free_fail;
178
179     memset(cmnd, 0xff, 12);
180     memset(gdtcmd, 0, sizeof(gdth_cmd_str));
181
182     TRACE2(("gdth_get_info() ha %d\n",ha->hanum));
183
184     
185     /* request is i.e. "cat /proc/scsi/gdth/0" */ 
186     /* format: %-15s\t%-10s\t%-15s\t%s */
187     /* driver parameters */
188     seq_puts(m, "Driver Parameters:\n");
189     if (reserve_list[0] == 0xff)
190         strcpy(hrec, "--");
191     else {
192         hlen = sprintf(hrec, "%d", reserve_list[0]);
193         for (i = 1;  i < MAX_RES_ARGS; i++) {
194             if (reserve_list[i] == 0xff) 
195                 break;
196             hlen += scnprintf(hrec + hlen, 161 - hlen, ",%d", reserve_list[i]);
197         }
198     }
199     seq_printf(m,
200                    " reserve_mode: \t%d         \treserve_list:  \t%s\n",
201                    reserve_mode, hrec);
202     seq_printf(m,
203                    " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
204                    max_ids, hdr_channel);
205
206     /* controller information */
207     seq_puts(m, "\nDisk Array Controller Information:\n");
208     seq_printf(m,
209                    " Number:       \t%d         \tName:          \t%s\n",
210                    ha->hanum, ha->binfo.type_string);
211
212     seq_printf(m,
213                    " Driver Ver.:  \t%-10s\tFirmware Ver.: \t",
214                    GDTH_VERSION_STR);
215     if (ha->more_proc)
216         seq_printf(m, "%d.%02d.%02d-%c%03X\n", 
217                 (u8)(ha->binfo.upd_fw_ver>>24),
218                 (u8)(ha->binfo.upd_fw_ver>>16),
219                 (u8)(ha->binfo.upd_fw_ver),
220                 ha->bfeat.raid ? 'R':'N',
221                 ha->binfo.upd_revision);
222     else
223         seq_printf(m, "%d.%02d\n", (u8)(ha->cpar.version>>8),
224                 (u8)(ha->cpar.version));
225  
226     if (ha->more_proc)
227         /* more information: 1. about controller */
228         seq_printf(m,
229                        " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
230                        ha->binfo.ser_no, ha->binfo.memsize / 1024);
231
232     if (ha->more_proc) {
233         size_t size = max_t(size_t, GDTH_SCRATCH, sizeof(gdth_hget_str));
234
235         /* more information: 2. about physical devices */
236         seq_puts(m, "\nPhysical Devices:");
237         flag = FALSE;
238             
239         buf = dma_alloc_coherent(&ha->pdev->dev, size, &paddr, GFP_KERNEL);
240         if (!buf) 
241             goto stop_output;
242         for (i = 0; i < ha->bus_cnt; ++i) {
243             /* 2.a statistics (and retries/reassigns) */
244             TRACE2(("pdr_statistics() chn %d\n",i));                
245             pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
246             gdtcmd->Service = CACHESERVICE;
247             gdtcmd->OpCode = GDT_IOCTL;
248             gdtcmd->u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
249             gdtcmd->u.ioctl.param_size = 3*GDTH_SCRATCH/4;
250             gdtcmd->u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
251             gdtcmd->u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
252             pds->bid = ha->raw[i].local_no;
253             pds->first = 0;
254             pds->entries = ha->raw[i].pdev_cnt;
255             cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(u32)) /
256                 sizeof(pds->list[0]);
257             if (pds->entries > cnt)
258                 pds->entries = cnt;
259
260             if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) != S_OK)
261                 pds->count = 0;
262
263             /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
264             for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
265                 /* 2.b drive info */
266                 TRACE2(("scsi_drv_info() chn %d dev %d\n",
267                     i, ha->raw[i].id_list[j]));             
268                 pdi = (gdth_diskinfo_str *)buf;
269                 gdtcmd->Service = CACHESERVICE;
270                 gdtcmd->OpCode = GDT_IOCTL;
271                 gdtcmd->u.ioctl.p_param = paddr;
272                 gdtcmd->u.ioctl.param_size = sizeof(gdth_diskinfo_str);
273                 gdtcmd->u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
274                 gdtcmd->u.ioctl.channel = 
275                     ha->raw[i].address | ha->raw[i].id_list[j];
276
277                 if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
278                     strncpy(hrec,pdi->vendor,8);
279                     strncpy(hrec+8,pdi->product,16);
280                     strncpy(hrec+24,pdi->revision,4);
281                     hrec[28] = 0;
282                     seq_printf(m,
283                                    "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
284                                    'A'+i,pdi->target_id,pdi->lun,hrec);
285                     flag = TRUE;
286                     pdi->no_ldrive &= 0xffff;
287                     if (pdi->no_ldrive == 0xffff)
288                         strcpy(hrec,"--");
289                     else
290                         sprintf(hrec,"%d",pdi->no_ldrive);
291                     seq_printf(m,
292                                    " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
293                                    pdi->blkcnt/(1024*1024/pdi->blksize),
294                                    hrec);
295                 } else {
296                     pdi->devtype = 0xff;
297                 }
298                     
299                 if (pdi->devtype == 0) {
300                     /* search retries/reassigns */
301                     for (k = 0; k < pds->count; ++k) {
302                         if (pds->list[k].tid == pdi->target_id &&
303                             pds->list[k].lun == pdi->lun) {
304                             seq_printf(m,
305                                            " Retries:      \t%-6d    \tReassigns:     \t%d\n",
306                                            pds->list[k].retries,
307                                            pds->list[k].reassigns);
308                             break;
309                         }
310                     }
311                     /* 2.c grown defects */
312                     TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
313                             i, ha->raw[i].id_list[j]));             
314                     pdef = (gdth_defcnt_str *)buf;
315                     gdtcmd->Service = CACHESERVICE;
316                     gdtcmd->OpCode = GDT_IOCTL;
317                     gdtcmd->u.ioctl.p_param = paddr;
318                     gdtcmd->u.ioctl.param_size = sizeof(gdth_defcnt_str);
319                     gdtcmd->u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
320                     gdtcmd->u.ioctl.channel = 
321                         ha->raw[i].address | ha->raw[i].id_list[j];
322                     pdef->sddc_type = 0x08;
323
324                     if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
325                         seq_printf(m,
326                                        " Grown Defects:\t%d\n",
327                                        pdef->sddc_cnt);
328                     }
329                 }
330             }
331         }
332
333         if (!flag)
334             seq_puts(m, "\n --\n");
335
336         /* 3. about logical drives */
337         seq_puts(m, "\nLogical Drives:");
338         flag = FALSE;
339
340         for (i = 0; i < MAX_LDRIVES; ++i) {
341             if (!ha->hdr[i].is_logdrv)
342                 continue;
343             drv_no = i;
344             j = k = 0;
345             is_mirr = FALSE;
346             do {
347                 /* 3.a log. drive info */
348                 TRACE2(("cache_drv_info() drive no %d\n",drv_no));
349                 pcdi = (gdth_cdrinfo_str *)buf;
350                 gdtcmd->Service = CACHESERVICE;
351                 gdtcmd->OpCode = GDT_IOCTL;
352                 gdtcmd->u.ioctl.p_param = paddr;
353                 gdtcmd->u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
354                 gdtcmd->u.ioctl.subfunc = CACHE_DRV_INFO;
355                 gdtcmd->u.ioctl.channel = drv_no;
356                 if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) != S_OK)
357                     break;
358                 pcdi->ld_dtype >>= 16;
359                 j++;
360                 if (pcdi->ld_dtype > 2) {
361                     strcpy(hrec, "missing");
362                 } else if (pcdi->ld_error & 1) {
363                     strcpy(hrec, "fault");
364                 } else if (pcdi->ld_error & 2) {
365                     strcpy(hrec, "invalid");
366                     k++; j--;
367                 } else {
368                     strcpy(hrec, "ok");
369                 }
370                     
371                 if (drv_no == i) {
372                     seq_printf(m,
373                                    "\n Number:       \t%-2d        \tStatus:        \t%s\n",
374                                    drv_no, hrec);
375                     flag = TRUE;
376                     no_mdrv = pcdi->cd_ldcnt;
377                     if (no_mdrv > 1 || pcdi->ld_slave != -1) {
378                         is_mirr = TRUE;
379                         strcpy(hrec, "RAID-1");
380                     } else if (pcdi->ld_dtype == 0) {
381                         strcpy(hrec, "Disk");
382                     } else if (pcdi->ld_dtype == 1) {
383                         strcpy(hrec, "RAID-0");
384                     } else if (pcdi->ld_dtype == 2) {
385                         strcpy(hrec, "Chain");
386                     } else {
387                         strcpy(hrec, "???");
388                     }
389                     seq_printf(m,
390                                    " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
391                                    pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
392                                    hrec);
393                 } else {
394                     seq_printf(m,
395                                    " Slave Number: \t%-2d        \tStatus:        \t%s\n",
396                                    drv_no & 0x7fff, hrec);
397                 }
398                 drv_no = pcdi->ld_slave;
399             } while (drv_no != -1);
400              
401             if (is_mirr)
402                 seq_printf(m,
403                                " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
404                                no_mdrv - j - k, k);
405
406             if (!ha->hdr[i].is_arraydrv)
407                 strcpy(hrec, "--");
408             else
409                 sprintf(hrec, "%d", ha->hdr[i].master_no);
410             seq_printf(m,
411                            " To Array Drv.:\t%s\n", hrec);
412         }       
413
414         if (!flag)
415             seq_puts(m, "\n --\n");
416
417         /* 4. about array drives */
418         seq_puts(m, "\nArray Drives:");
419         flag = FALSE;
420
421         for (i = 0; i < MAX_LDRIVES; ++i) {
422             if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
423                 continue;
424             /* 4.a array drive info */
425             TRACE2(("array_info() drive no %d\n",i));
426             pai = (gdth_arrayinf_str *)buf;
427             gdtcmd->Service = CACHESERVICE;
428             gdtcmd->OpCode = GDT_IOCTL;
429             gdtcmd->u.ioctl.p_param = paddr;
430             gdtcmd->u.ioctl.param_size = sizeof(gdth_arrayinf_str);
431             gdtcmd->u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
432             gdtcmd->u.ioctl.channel = i;
433             if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
434                 if (pai->ai_state == 0)
435                     strcpy(hrec, "idle");
436                 else if (pai->ai_state == 2)
437                     strcpy(hrec, "build");
438                 else if (pai->ai_state == 4)
439                     strcpy(hrec, "ready");
440                 else if (pai->ai_state == 6)
441                     strcpy(hrec, "fail");
442                 else if (pai->ai_state == 8 || pai->ai_state == 10)
443                     strcpy(hrec, "rebuild");
444                 else
445                     strcpy(hrec, "error");
446                 if (pai->ai_ext_state & 0x10)
447                     strcat(hrec, "/expand");
448                 else if (pai->ai_ext_state & 0x1)
449                     strcat(hrec, "/patch");
450                 seq_printf(m,
451                                "\n Number:       \t%-2d        \tStatus:        \t%s\n",
452                                i,hrec);
453                 flag = TRUE;
454
455                 if (pai->ai_type == 0)
456                     strcpy(hrec, "RAID-0");
457                 else if (pai->ai_type == 4)
458                     strcpy(hrec, "RAID-4");
459                 else if (pai->ai_type == 5)
460                     strcpy(hrec, "RAID-5");
461                 else 
462                     strcpy(hrec, "RAID-10");
463                 seq_printf(m,
464                                " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
465                                pai->ai_size/(1024*1024/pai->ai_secsize),
466                                hrec);
467             }
468         }
469
470         if (!flag)
471             seq_puts(m, "\n --\n");
472
473         /* 5. about host drives */
474         seq_puts(m, "\nHost Drives:");
475         flag = FALSE;
476
477         for (i = 0; i < MAX_LDRIVES; ++i) {
478             if (!ha->hdr[i].is_logdrv || 
479                 (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
480                 continue;
481             /* 5.a get host drive list */
482             TRACE2(("host_get() drv_no %d\n",i));           
483             phg = (gdth_hget_str *)buf;
484             gdtcmd->Service = CACHESERVICE;
485             gdtcmd->OpCode = GDT_IOCTL;
486             gdtcmd->u.ioctl.p_param = paddr;
487             gdtcmd->u.ioctl.param_size = sizeof(gdth_hget_str);
488             gdtcmd->u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
489             gdtcmd->u.ioctl.channel = i;
490             phg->entries = MAX_HDRIVES;
491             phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
492             if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
493                 ha->hdr[i].ldr_no = i;
494                 ha->hdr[i].rw_attribs = 0;
495                 ha->hdr[i].start_sec = 0;
496             } else {
497                 for (j = 0; j < phg->entries; ++j) {
498                     k = phg->entry[j].host_drive;
499                     if (k >= MAX_LDRIVES)
500                         continue;
501                     ha->hdr[k].ldr_no = phg->entry[j].log_drive;
502                     ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
503                     ha->hdr[k].start_sec = phg->entry[j].start_sec;
504                 }
505             }
506         }
507         dma_free_coherent(&ha->pdev->dev, size, buf, paddr);
508
509         for (i = 0; i < MAX_HDRIVES; ++i) {
510             if (!(ha->hdr[i].present))
511                 continue;
512               
513             seq_printf(m,
514                            "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
515                            i, ha->hdr[i].ldr_no);
516             flag = TRUE;
517
518             seq_printf(m,
519                            " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
520                            (u32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
521         }
522         
523         if (!flag)
524             seq_puts(m, "\n --\n");
525     }
526
527     /* controller events */
528     seq_puts(m, "\nController Events:\n");
529
530     for (id = -1;;) {
531         id = gdth_read_event(ha, id, estr);
532         if (estr->event_source == 0)
533             break;
534         if (estr->event_data.eu.driver.ionode == ha->hanum &&
535             estr->event_source == ES_ASYNC) { 
536             gdth_log_event(&estr->event_data, hrec);
537
538             /*
539              * Elapsed seconds subtraction with unsigned operands is
540              * safe from wrap around in year 2106.  Executes as:
541              * operand a + (2's complement operand b) + 1
542              */
543
544             sec = (int)((u32)ktime_get_real_seconds() - estr->first_stamp);
545             if (sec < 0) sec = 0;
546             seq_printf(m," date- %02d:%02d:%02d\t%s\n",
547                            sec/3600, sec%3600/60, sec%60, hrec);
548         }
549         if (id == -1)
550             break;
551     }
552 stop_output:
553     rc = 0;
554 free_fail:
555     kfree(gdtcmd);
556     kfree(estr);
557     return rc;
558 }
559
560 static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
561 {
562     unsigned long flags;
563     int i;
564     struct scsi_cmnd *scp;
565     struct gdth_cmndinfo *cmndinfo;
566     u8 b, t;
567
568     spin_lock_irqsave(&ha->smp_lock, flags);
569
570     for (i = 0; i < GDTH_MAXCMDS; ++i) {
571         scp = ha->cmd_tab[i].cmnd;
572         cmndinfo = gdth_cmnd_priv(scp);
573
574         b = scp->device->channel;
575         t = scp->device->id;
576         if (!SPECIAL_SCP(scp) && t == (u8)id && 
577             b == (u8)busnum) {
578             cmndinfo->wait_for_completion = 0;
579             spin_unlock_irqrestore(&ha->smp_lock, flags);
580             while (!cmndinfo->wait_for_completion)
581                 barrier();
582             spin_lock_irqsave(&ha->smp_lock, flags);
583         }
584     }
585     spin_unlock_irqrestore(&ha->smp_lock, flags);
586 }