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