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