patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / scsi / gdth_proc.c
1 /* gdth_proc.c 
2  * $Id: gdth_proc.c,v 1.42 2004/03/05 15:50:20 achim Exp $
3  */
4
5 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
6 #include <linux/completion.h>
7 #endif
8
9 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
10 int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,   
11                    int inout)
12 {
13     int hanum,busnum;
14
15     TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
16             length,(int)offset,inout));
17
18     hanum = NUMDATA(host)->hanum;
19     busnum= NUMDATA(host)->busnum;
20
21     if (inout)
22         return(gdth_set_info(buffer,length,host,hanum,busnum));
23     else
24         return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum));
25 }
26 #else
27 int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno,   
28                    int inout)
29 {
30     int hanum,busnum,i;
31
32     TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
33             length,(int)offset,inout));
34
35     for (i = 0; i < gdth_ctr_vcount; ++i) {
36         if (gdth_ctr_vtab[i]->host_no == hostno)
37             break;
38     }
39     if (i == gdth_ctr_vcount)
40         return(-EINVAL);
41
42     hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
43     busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
44
45     if (inout)
46         return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum));
47     else
48         return(gdth_get_info(buffer,start,offset,length,
49                              gdth_ctr_vtab[i],hanum,busnum));
50 }
51 #endif
52
53 static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
54                          int hanum,int busnum)
55 {
56     int             ret_val = -EINVAL;
57 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
58     Scsi_Request    *scp;
59     Scsi_Device     *sdev;
60 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
61     Scsi_Cmnd       *scp;
62     Scsi_Device     *sdev;
63 #else
64     Scsi_Cmnd       scp;
65     Scsi_Device     sdev;
66 #endif
67     TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
68
69 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
70     sdev = scsi_get_host_dev(host);
71     scp  = scsi_allocate_request(sdev, GFP_KERNEL);
72     if (!scp)
73         return -ENOMEM;
74     scp->sr_cmd_len = 12;
75     scp->sr_use_sg = 0;
76 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
77     sdev = scsi_get_host_dev(host);
78     scp  = scsi_allocate_device(sdev, 1, FALSE);
79     if (!scp)
80         return -ENOMEM;
81     scp->cmd_len = 12;
82     scp->use_sg = 0;
83 #else
84     memset(&sdev,0,sizeof(Scsi_Device));
85     memset(&scp, 0,sizeof(Scsi_Cmnd));
86     sdev.host = scp.host = host;
87     sdev.id = scp.target = sdev.host->this_id;
88     scp.device = &sdev;
89 #endif
90
91     if (length >= 4) {
92         if (strncmp(buffer,"gdth",4) == 0) {
93             buffer += 5;
94             length -= 5;
95             ret_val = gdth_set_asc_info( buffer, length, hanum, scp );
96         }
97     }
98 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
99     scsi_release_request(scp);
100     scsi_free_host_dev(sdev);
101 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
102     scsi_release_command(scp);
103     scsi_free_host_dev(sdev);
104 #endif
105     return ret_val;
106 }
107          
108 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
109 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp)
110 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
111 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
112 #else
113 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
114 #endif
115 {
116     int             orig_length, drive, wb_mode;
117     int             i, found;
118     gdth_ha_str     *ha;
119     gdth_cmd_str    gdtcmd;
120     gdth_cpar_str   *pcpar;
121     ulong64         paddr;
122
123     char            cmnd[MAX_COMMAND_SIZE];
124     memset(cmnd, 0xff, 12);
125     memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
126
127     TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
128     ha = HADATA(gdth_ctr_tab[hanum]);
129     orig_length = length + 5;
130     drive = -1;
131     wb_mode = 0;
132     found = FALSE;
133
134     if (length >= 5 && strncmp(buffer,"flush",5)==0) {
135         buffer += 6;
136         length -= 6;
137         if (length && *buffer>='0' && *buffer<='9') {
138             drive = (int)(*buffer-'0');
139             ++buffer; --length;
140             if (length && *buffer>='0' && *buffer<='9') {
141                 drive = drive*10 + (int)(*buffer-'0');
142                 ++buffer; --length;
143             }
144             printk("GDT: Flushing host drive %d .. ",drive);
145         } else {
146             printk("GDT: Flushing all host drives .. ");
147         }
148         for (i = 0; i < MAX_HDRIVES; ++i) {
149             if (ha->hdr[i].present) {
150                 if (drive != -1 && i != drive)
151                     continue;
152                 found = TRUE;
153                 gdtcmd.Service = CACHESERVICE;
154                 gdtcmd.OpCode = GDT_FLUSH;
155                 if (ha->cache_feat & GDT_64BIT) {
156                     gdtcmd.u.cache64.DeviceNo = i;
157                     gdtcmd.u.cache64.BlockNo = 1;
158                 } else {
159                     gdtcmd.u.cache.DeviceNo = i;
160                     gdtcmd.u.cache.BlockNo = 1;
161                 }
162 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
163                 gdth_do_req(scp, &gdtcmd, cmnd, 30);
164 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
165                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
166 #else
167                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
168 #endif
169             }
170         }
171         if (!found)
172             printk("\nNo host drive found !\n");
173         else
174             printk("Done.\n");
175         return(orig_length);
176     }
177
178     if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
179         buffer += 8;
180         length -= 8;
181         printk("GDT: Disabling write back permanently .. ");
182         wb_mode = 1;
183     } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
184         buffer += 7;
185         length -= 7;
186         printk("GDT: Enabling write back permanently .. ");
187         wb_mode = 2;
188     } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
189         buffer += 7;
190         length -= 7;
191         printk("GDT: Disabling write back commands .. ");
192         if (ha->cache_feat & GDT_WR_THROUGH) {
193             gdth_write_through = TRUE;
194             printk("Done.\n");
195         } else {
196             printk("Not supported !\n");
197         }
198         return(orig_length);
199     } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
200         buffer += 6;
201         length -= 6;
202         printk("GDT: Enabling write back commands .. ");
203         gdth_write_through = FALSE;
204         printk("Done.\n");
205         return(orig_length);
206     }
207
208     if (wb_mode) {
209         if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr))
210             return(-EBUSY);
211         pcpar = (gdth_cpar_str *)ha->pscratch;
212         memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
213         gdtcmd.Service = CACHESERVICE;
214         gdtcmd.OpCode = GDT_IOCTL;
215         gdtcmd.u.ioctl.p_param = paddr;
216         gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
217         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
218         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
219         pcpar->write_back = wb_mode==1 ? 0:1;
220 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
221         gdth_do_req(scp, &gdtcmd, cmnd, 30);
222 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
223         gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
224 #else
225         gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
226 #endif
227         gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr);
228         printk("Done.\n");
229         return(orig_length);
230     }
231
232     printk("GDT: Unknown command: %s  Length: %d\n",buffer,length);
233     return(-EINVAL);
234 }
235
236 static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
237                          struct Scsi_Host *host,int hanum,int busnum)
238 {
239     int size = 0,len = 0;
240     off_t begin = 0,pos = 0;
241     gdth_ha_str *ha;
242     int id, i, j, k, sec, flag;
243     int no_mdrv = 0, drv_no, is_mirr;
244     ulong32 cnt;
245     ulong64 paddr;
246
247     gdth_cmd_str gdtcmd;
248     gdth_evt_str estr;
249 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
250     Scsi_Request *scp;
251     Scsi_Device *sdev; 
252 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
253     Scsi_Cmnd *scp;
254     Scsi_Device *sdev;
255 #else
256     Scsi_Cmnd scp;
257     Scsi_Device sdev;
258 #endif
259     char hrec[161];
260     struct timeval tv;
261
262     char *buf;
263     gdth_dskstat_str *pds;
264     gdth_diskinfo_str *pdi;
265     gdth_arrayinf_str *pai;
266     gdth_defcnt_str *pdef;
267     gdth_cdrinfo_str *pcdi;
268     gdth_hget_str *phg;
269
270     char cmnd[MAX_COMMAND_SIZE];
271     memset(cmnd, 0xff, 12);
272     memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
273
274     TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
275     ha = HADATA(gdth_ctr_tab[hanum]);
276
277 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
278     sdev = scsi_get_host_dev(host);
279     scp  = scsi_allocate_request(sdev, GFP_KERNEL);
280     if (!scp)
281         return -ENOMEM;
282     scp->sr_cmd_len = 12;
283     scp->sr_use_sg = 0;
284 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
285     sdev = scsi_get_host_dev(host);
286     scp  = scsi_allocate_device(sdev, 1, FALSE);
287     if (!scp)
288         return -ENOMEM;
289     scp->cmd_len = 12;
290     scp->use_sg = 0;
291 #else
292     memset(&sdev,0,sizeof(Scsi_Device));
293     memset(&scp, 0,sizeof(Scsi_Cmnd));
294     sdev.host = scp.host = host;
295     sdev.id = scp.target = sdev.host->this_id;
296     scp.device = &sdev;
297 #endif
298     
299     
300     /* request is i.e. "cat /proc/scsi/gdth/0" */ 
301     /* format: %-15s\t%-10s\t%-15s\t%s */
302     /* driver parameters */
303     size = sprintf(buffer+len,"Driver Parameters:\n");
304     len += size;  pos = begin + len;
305     if (reserve_list[0] == 0xff)
306         strcpy(hrec, "--");
307     else {
308         sprintf(hrec, "%d", reserve_list[0]);
309         for (i = 1;  i < MAX_RES_ARGS; i++) {
310             if (reserve_list[i] == 0xff) 
311                 break;
312             sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
313         }
314     }
315     size = sprintf(buffer+len,
316                    " reserve_mode: \t%d         \treserve_list:  \t%s\n",
317                    reserve_mode, hrec);
318     len += size;  pos = begin + len;
319     size = sprintf(buffer+len,
320                    " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
321                    max_ids, hdr_channel);
322     len += size;  pos = begin + len;
323
324     /* controller information */
325     size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
326     len += size;  pos = begin + len;
327     if (virt_ctr)
328         sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
329     else
330         strcpy(hrec, ha->binfo.type_string);
331     size = sprintf(buffer+len,
332                    " Number:       \t%d         \tName:          \t%s\n",
333                    hanum, hrec);
334     len += size;  pos = begin + len;
335
336     if (ha->more_proc)
337         sprintf(hrec, "%d.%02d.%02d-%c%03X", 
338                 (unchar)(ha->binfo.upd_fw_ver>>24),
339                 (unchar)(ha->binfo.upd_fw_ver>>16),
340                 (unchar)(ha->binfo.upd_fw_ver),
341                 ha->bfeat.raid ? 'R':'N',
342                 ha->binfo.upd_revision);
343     else
344         sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
345                 (unchar)(ha->cpar.version));
346
347     size = sprintf(buffer+len,
348                    " Driver Ver.:  \t%-10s\tFirmware Ver.: \t%s\n",
349                    GDTH_VERSION_STR, hrec);
350     len += size;  pos = begin + len;
351  
352     if (ha->more_proc) {
353         /* more information: 1. about controller */
354         size = sprintf(buffer+len,
355                        " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
356                        ha->binfo.ser_no, ha->binfo.memsize / 1024);
357         len += size;  pos = begin + len;
358     }
359
360 #ifdef GDTH_DMA_STATISTICS
361     /* controller statistics */
362     size = sprintf(buffer+len,"\nController Statistics:\n");
363     len += size;  pos = begin + len;
364     size = sprintf(buffer+len,
365                    " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n",
366                    ha->dma32_cnt, ha->dma64_cnt);
367     len += size;  pos = begin + len;
368 #endif
369
370     if (pos < offset) {
371         len = 0;
372         begin = pos;
373     }
374     if (pos > offset + length)
375         goto stop_output;
376
377     if (ha->more_proc) {
378         /* more information: 2. about physical devices */
379         size = sprintf(buffer+len,"\nPhysical Devices:");
380         len += size;  pos = begin + len;
381         flag = FALSE;
382             
383         buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
384         if (!buf) 
385             goto stop_output;
386         for (i = 0; i < ha->bus_cnt; ++i) {
387             /* 2.a statistics (and retries/reassigns) */
388             TRACE2(("pdr_statistics() chn %d\n",i));                
389             pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
390             gdtcmd.Service = CACHESERVICE;
391             gdtcmd.OpCode = GDT_IOCTL;
392             gdtcmd.u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
393             gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4;
394             gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
395             gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
396             pds->bid = ha->raw[i].local_no;
397             pds->first = 0;
398             pds->entries = ha->raw[i].pdev_cnt;
399             cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
400                 sizeof(pds->list[0]);
401             if (pds->entries > cnt)
402                 pds->entries = cnt;
403 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
404             gdth_do_req(scp, &gdtcmd, cmnd, 30);
405             if (scp->sr_command->SCp.Status != S_OK) 
406 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
407             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
408             if (scp->SCp.Status != S_OK) 
409 #else
410             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
411             if (scp.SCp.Status != S_OK) 
412 #endif
413             { 
414                 pds->count = 0;
415             }
416
417             /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
418             for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
419                 /* 2.b drive info */
420                 TRACE2(("scsi_drv_info() chn %d dev %d\n",
421                     i, ha->raw[i].id_list[j]));             
422                 pdi = (gdth_diskinfo_str *)buf;
423                 gdtcmd.Service = CACHESERVICE;
424                 gdtcmd.OpCode = GDT_IOCTL;
425                 gdtcmd.u.ioctl.p_param = paddr;
426                 gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str);
427                 gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
428                 gdtcmd.u.ioctl.channel = 
429                     ha->raw[i].address | ha->raw[i].id_list[j];
430 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
431                 gdth_do_req(scp, &gdtcmd, cmnd, 30);
432                 if (scp->sr_command->SCp.Status == S_OK) 
433 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
434                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
435                 if (scp->SCp.Status == S_OK) 
436 #else
437                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
438                 if (scp.SCp.Status == S_OK) 
439 #endif
440                 {
441                     strncpy(hrec,pdi->vendor,8);
442                     strncpy(hrec+8,pdi->product,16);
443                     strncpy(hrec+24,pdi->revision,4);
444                     hrec[28] = 0;
445                     size = sprintf(buffer+len,
446                                    "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
447                                    'A'+i,pdi->target_id,pdi->lun,hrec);
448                     len += size;  pos = begin + len;
449                     flag = TRUE;
450                     pdi->no_ldrive &= 0xffff;
451                     if (pdi->no_ldrive == 0xffff)
452                         strcpy(hrec,"--");
453                     else
454                         sprintf(hrec,"%d",pdi->no_ldrive);
455                     size = sprintf(buffer+len,
456                                    " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
457                                    pdi->blkcnt/(1024*1024/pdi->blksize),
458                                    hrec);
459                     len += size;  pos = begin + len;
460                 } else {
461                     pdi->devtype = 0xff;
462                 }
463                     
464                 if (pdi->devtype == 0) {
465                     /* search retries/reassigns */
466                     for (k = 0; k < pds->count; ++k) {
467                         if (pds->list[k].tid == pdi->target_id &&
468                             pds->list[k].lun == pdi->lun) {
469                             size = sprintf(buffer+len,
470                                            " Retries:      \t%-6d    \tReassigns:     \t%d\n",
471                                            pds->list[k].retries,
472                                            pds->list[k].reassigns);
473                             len += size;  pos = begin + len;
474                             break;
475                         }
476                     }
477                     /* 2.c grown defects */
478                     TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
479                             i, ha->raw[i].id_list[j]));             
480                     pdef = (gdth_defcnt_str *)buf;
481                     gdtcmd.Service = CACHESERVICE;
482                     gdtcmd.OpCode = GDT_IOCTL;
483                     gdtcmd.u.ioctl.p_param = paddr;
484                     gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str);
485                     gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
486                     gdtcmd.u.ioctl.channel = 
487                         ha->raw[i].address | ha->raw[i].id_list[j];
488                     pdef->sddc_type = 0x08;
489 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
490                     gdth_do_req(scp, &gdtcmd, cmnd, 30);
491                     if (scp->sr_command->SCp.Status == S_OK) 
492 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
493                     gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
494                     if (scp->SCp.Status == S_OK) 
495 #else
496                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
497                     if (scp.SCp.Status == S_OK) 
498 #endif
499                     {
500                         size = sprintf(buffer+len,
501                                        " Grown Defects:\t%d\n",
502                                        pdef->sddc_cnt);
503                         len += size;  pos = begin + len;
504                     }
505                 }
506                 if (pos < offset) {
507                     len = 0;
508                     begin = pos;
509                 }
510                 if (pos > offset + length)
511                     goto stop_output;
512             }
513         }
514         gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
515
516         if (!flag) {
517             size = sprintf(buffer+len, "\n --\n");
518             len += size;  pos = begin + len;
519         }
520
521         /* 3. about logical drives */
522         size = sprintf(buffer+len,"\nLogical Drives:");
523         len += size;  pos = begin + len;
524         flag = FALSE;
525
526         buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
527         if (!buf) 
528             goto stop_output;
529         for (i = 0; i < MAX_LDRIVES; ++i) {
530             if (!ha->hdr[i].is_logdrv)
531                 continue;
532             drv_no = i;
533             j = k = 0;
534             is_mirr = FALSE;
535             do {
536                 /* 3.a log. drive info */
537                 TRACE2(("cache_drv_info() drive no %d\n",drv_no));
538                 pcdi = (gdth_cdrinfo_str *)buf;
539                 gdtcmd.Service = CACHESERVICE;
540                 gdtcmd.OpCode = GDT_IOCTL;
541                 gdtcmd.u.ioctl.p_param = paddr;
542                 gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
543                 gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
544                 gdtcmd.u.ioctl.channel = drv_no;
545 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
546                 gdth_do_req(scp, &gdtcmd, cmnd, 30);
547                 if (scp->sr_command->SCp.Status != S_OK) 
548 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
549                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
550                 if (scp->SCp.Status != S_OK)
551 #else
552                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
553                 if (scp.SCp.Status != S_OK)
554 #endif
555                 {
556                     break;
557                 }
558                 pcdi->ld_dtype >>= 16;
559                 j++;
560                 if (pcdi->ld_dtype > 2) {
561                     strcpy(hrec, "missing");
562                 } else if (pcdi->ld_error & 1) {
563                     strcpy(hrec, "fault");
564                 } else if (pcdi->ld_error & 2) {
565                     strcpy(hrec, "invalid");
566                     k++; j--;
567                 } else {
568                     strcpy(hrec, "ok");
569                 }
570                     
571                 if (drv_no == i) {
572                     size = sprintf(buffer+len,
573                                    "\n Number:       \t%-2d        \tStatus:        \t%s\n",
574                                    drv_no, hrec);
575                     len += size;  pos = begin + len;
576                     flag = TRUE;
577                     no_mdrv = pcdi->cd_ldcnt;
578                     if (no_mdrv > 1 || pcdi->ld_slave != -1) {
579                         is_mirr = TRUE;
580                         strcpy(hrec, "RAID-1");
581                     } else if (pcdi->ld_dtype == 0) {
582                         strcpy(hrec, "Disk");
583                     } else if (pcdi->ld_dtype == 1) {
584                         strcpy(hrec, "RAID-0");
585                     } else if (pcdi->ld_dtype == 2) {
586                         strcpy(hrec, "Chain");
587                     } else {
588                         strcpy(hrec, "???");
589                     }
590                     size = sprintf(buffer+len,
591                                    " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
592                                    pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
593                                    hrec);
594                     len += size;  pos = begin + len;
595                 } else {
596                     size = sprintf(buffer+len,
597                                    " Slave Number: \t%-2d        \tStatus:        \t%s\n",
598                                    drv_no & 0x7fff, hrec);
599                     len += size;  pos = begin + len;
600                 }
601                 drv_no = pcdi->ld_slave;
602                 if (pos < offset) {
603                     len = 0;
604                     begin = pos;
605                 }
606                 if (pos > offset + length)
607                     goto stop_output;
608             } while (drv_no != -1);
609              
610             if (is_mirr) {
611                 size = sprintf(buffer+len,
612                                " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
613                                no_mdrv - j - k, k);
614                 len += size;  pos = begin + len;
615             }
616               
617             if (!ha->hdr[i].is_arraydrv)
618                 strcpy(hrec, "--");
619             else
620                 sprintf(hrec, "%d", ha->hdr[i].master_no);
621             size = sprintf(buffer+len,
622                            " To Array Drv.:\t%s\n", hrec);
623             len += size;  pos = begin + len;
624             if (pos < offset) {
625                 len = 0;
626                 begin = pos;
627             }
628             if (pos > offset + length)
629                 goto stop_output;
630         }       
631         gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
632         
633         if (!flag) {
634             size = sprintf(buffer+len, "\n --\n");
635             len += size;  pos = begin + len;
636         }   
637
638         /* 4. about array drives */
639         size = sprintf(buffer+len,"\nArray Drives:");
640         len += size;  pos = begin + len;
641         flag = FALSE;
642
643         buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
644         if (!buf) 
645             goto stop_output;
646         for (i = 0; i < MAX_LDRIVES; ++i) {
647             if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
648                 continue;
649             /* 4.a array drive info */
650             TRACE2(("array_info() drive no %d\n",i));
651             pai = (gdth_arrayinf_str *)buf;
652             gdtcmd.Service = CACHESERVICE;
653             gdtcmd.OpCode = GDT_IOCTL;
654             gdtcmd.u.ioctl.p_param = paddr;
655             gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
656             gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
657             gdtcmd.u.ioctl.channel = i;
658 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
659             gdth_do_req(scp, &gdtcmd, cmnd, 30);
660             if (scp->sr_command->SCp.Status == S_OK) 
661 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
662             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
663             if (scp->SCp.Status == S_OK) 
664 #else
665             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
666             if (scp.SCp.Status == S_OK) 
667 #endif
668             {
669                 if (pai->ai_state == 0)
670                     strcpy(hrec, "idle");
671                 else if (pai->ai_state == 2)
672                     strcpy(hrec, "build");
673                 else if (pai->ai_state == 4)
674                     strcpy(hrec, "ready");
675                 else if (pai->ai_state == 6)
676                     strcpy(hrec, "fail");
677                 else if (pai->ai_state == 8 || pai->ai_state == 10)
678                     strcpy(hrec, "rebuild");
679                 else
680                     strcpy(hrec, "error");
681                 if (pai->ai_ext_state & 0x10)
682                     strcat(hrec, "/expand");
683                 else if (pai->ai_ext_state & 0x1)
684                     strcat(hrec, "/patch");
685                 size = sprintf(buffer+len,
686                                "\n Number:       \t%-2d        \tStatus:        \t%s\n",
687                                i,hrec);
688                 len += size;  pos = begin + len;
689                 flag = TRUE;
690
691                 if (pai->ai_type == 0)
692                     strcpy(hrec, "RAID-0");
693                 else if (pai->ai_type == 4)
694                     strcpy(hrec, "RAID-4");
695                 else if (pai->ai_type == 5)
696                     strcpy(hrec, "RAID-5");
697                 else 
698                     strcpy(hrec, "RAID-10");
699                 size = sprintf(buffer+len,
700                                " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
701                                pai->ai_size/(1024*1024/pai->ai_secsize),
702                                hrec);
703                 len += size;  pos = begin + len;
704                 if (pos < offset) {
705                     len = 0;
706                     begin = pos;
707                 }
708                 if (pos > offset + length)
709                     goto stop_output;
710             }
711         }
712         gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
713         
714         if (!flag) {
715             size = sprintf(buffer+len, "\n --\n");
716             len += size;  pos = begin + len;
717         }
718
719         /* 5. about host drives */
720         size = sprintf(buffer+len,"\nHost Drives:");
721         len += size;  pos = begin + len;
722         flag = FALSE;
723
724         buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
725         if (!buf) 
726             goto stop_output;
727         for (i = 0; i < MAX_LDRIVES; ++i) {
728             if (!ha->hdr[i].is_logdrv || 
729                 (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
730                 continue;
731             /* 5.a get host drive list */
732             TRACE2(("host_get() drv_no %d\n",i));           
733             phg = (gdth_hget_str *)buf;
734             gdtcmd.Service = CACHESERVICE;
735             gdtcmd.OpCode = GDT_IOCTL;
736             gdtcmd.u.ioctl.p_param = paddr;
737             gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str);
738             gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
739             gdtcmd.u.ioctl.channel = i;
740             phg->entries = MAX_HDRIVES;
741             phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
742 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
743             gdth_do_req(scp, &gdtcmd, cmnd, 30);
744             if (scp->sr_command->SCp.Status != S_OK) 
745 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
746             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
747             if (scp->SCp.Status != S_OK) 
748 #else
749             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
750             if (scp.SCp.Status != S_OK) 
751 #endif
752             {
753                 ha->hdr[i].ldr_no = i;
754                 ha->hdr[i].rw_attribs = 0;
755                 ha->hdr[i].start_sec = 0;
756             } else {
757                 for (j = 0; j < phg->entries; ++j) {
758                     k = phg->entry[j].host_drive;
759                     if (k >= MAX_LDRIVES)
760                         continue;
761                     ha->hdr[k].ldr_no = phg->entry[j].log_drive;
762                     ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
763                     ha->hdr[k].start_sec = phg->entry[j].start_sec;
764                 }
765             }
766         }
767         gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
768
769         for (i = 0; i < MAX_HDRIVES; ++i) {
770             if (!(ha->hdr[i].present))
771                 continue;
772               
773             size = sprintf(buffer+len,
774                            "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
775                            i, ha->hdr[i].ldr_no);
776             len += size;  pos = begin + len;
777             flag = TRUE;
778
779             size = sprintf(buffer+len,
780                            " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
781                            (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
782             len += size;  pos = begin + len;
783             if (pos < offset) {
784                 len = 0;
785                 begin = pos;
786             }
787             if (pos > offset + length)
788                 goto stop_output;
789         }
790         
791         if (!flag) {
792             size = sprintf(buffer+len, "\n --\n");
793             len += size;  pos = begin + len;
794         }
795     }
796
797     /* controller events */
798     size = sprintf(buffer+len,"\nController Events:\n");
799     len += size;  pos = begin + len;
800
801     for (id = -1;;) {
802         id = gdth_read_event(ha, id, &estr);
803         if (estr.event_source == 0)
804             break;
805         if (estr.event_data.eu.driver.ionode == hanum &&
806             estr.event_source == ES_ASYNC) { 
807             gdth_log_event(&estr.event_data, hrec);
808             do_gettimeofday(&tv);
809             sec = (int)(tv.tv_sec - estr.first_stamp);
810             if (sec < 0) sec = 0;
811             size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
812                            sec/3600, sec%3600/60, sec%60, hrec);
813             len += size;  pos = begin + len;
814             if (pos < offset) {
815                 len = 0;
816                 begin = pos;
817             }
818             if (pos > offset + length)
819                 goto stop_output;
820         }
821         if (id == -1)
822             break;
823     }
824
825 stop_output:
826 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
827     scsi_release_request(scp);
828     scsi_free_host_dev(sdev);
829 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
830     scsi_release_command(scp);
831     scsi_free_host_dev(sdev);
832 #endif
833     *start = buffer +(offset-begin);
834     len -= (offset-begin);
835     if (len > length)
836         len = length;
837     TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n",
838             len,(int)pos,(int)begin,(int)offset,length,size));
839     return(len);
840 }
841
842
843 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
844 static void gdth_do_req(Scsi_Request *scp, gdth_cmd_str *gdtcmd, 
845                         char *cmnd, int timeout)
846 {
847     unsigned bufflen;
848     DECLARE_COMPLETION(wait);
849
850     TRACE2(("gdth_do_req()\n"));
851     if (gdtcmd != NULL) { 
852         bufflen = sizeof(gdth_cmd_str);
853     } else {
854         bufflen = 0;
855     }
856     scp->sr_request->rq_status = RQ_SCSI_BUSY;
857     scp->sr_request->waiting = &wait;
858     scsi_do_req(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
859     wait_for_completion(&wait);
860 }
861
862 #else
863 static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 
864                         char *cmnd, int timeout)
865 {
866     unsigned bufflen;
867 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
868     DECLARE_COMPLETION(wait);
869 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
870     DECLARE_MUTEX_LOCKED(sem);
871 #else
872     struct semaphore sem = MUTEX_LOCKED;
873 #endif
874
875     TRACE2(("gdth_do_cmd()\n"));
876     if (gdtcmd != NULL) { 
877         scp->SCp.this_residual = IOCTL_PRI;
878         bufflen = sizeof(gdth_cmd_str);
879     } else {
880         scp->SCp.this_residual = DEFAULT_PRI;
881         bufflen = 0;
882     }
883 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
884     scp->request.rq_status = RQ_SCSI_BUSY;
885     scp->request.waiting = &wait;
886     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
887     wait_for_completion(&wait);
888 #else
889     scp->request.sem = &sem;
890 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
891     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
892 #else
893     spin_lock_irq(&io_request_lock);
894     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
895     spin_unlock_irq(&io_request_lock);
896 #endif
897     down(&sem);
898 #endif
899 }
900 #endif
901
902 void gdth_scsi_done(Scsi_Cmnd *scp)
903 {
904     TRACE2(("gdth_scsi_done()\n"));
905
906 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
907     scp->request->rq_status = RQ_SCSI_DONE;
908     if (scp->request->waiting != NULL)
909         complete(scp->request->waiting);
910 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
911     scp->request.rq_status = RQ_SCSI_DONE;
912     if (scp->request.waiting != NULL)
913         complete(scp->request.waiting);
914 #else
915     scp->request.rq_status = RQ_SCSI_DONE;
916     if (scp->request.sem != NULL)
917         up(scp->request.sem);
918 #endif
919 }
920
921 static char *gdth_ioctl_alloc(int hanum, int size, int scratch, 
922                               ulong64 *paddr)
923 {
924     gdth_ha_str *ha;
925     ulong flags;
926     char *ret_val;
927
928     if (size == 0)
929         return NULL;
930
931     ha = HADATA(gdth_ctr_tab[hanum]);
932     GDTH_LOCK_HA(ha, flags);
933
934     if (!ha->scratch_busy && size <= GDTH_SCRATCH) {
935         ha->scratch_busy = TRUE;
936         ret_val = ha->pscratch;
937         *paddr = ha->scratch_phys;
938     } else if (scratch) {
939         ret_val = NULL;
940     } else {
941 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
942         dma_addr_t dma_addr;
943
944         ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr);
945         *paddr = dma_addr;
946 #else
947         ret_val = scsi_init_malloc(size, GFP_ATOMIC | GFP_DMA);
948         if (ret_val)
949             *paddr = virt_to_bus(ret_val);
950 #endif
951     }
952
953     GDTH_UNLOCK_HA(ha, flags);
954     return ret_val;
955 }
956
957 static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
958 {
959     gdth_ha_str *ha;
960     ulong flags;
961
962     ha = HADATA(gdth_ctr_tab[hanum]);
963     GDTH_LOCK_HA(ha, flags);
964
965     if (buf == ha->pscratch) {
966         ha->scratch_busy = FALSE;
967     } else {
968 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
969         pci_free_consistent(ha->pdev, size, buf, paddr);
970 #else
971         scsi_init_free((void *)buf, size);
972 #endif
973     }
974
975     GDTH_UNLOCK_HA(ha, flags);
976 }
977
978 #ifdef GDTH_IOCTL_PROC
979 static int gdth_ioctl_check_bin(int hanum, ushort size)
980 {
981     gdth_ha_str *ha;
982     ulong flags;
983     int ret_val;
984
985     ha = HADATA(gdth_ctr_tab[hanum]);
986     GDTH_LOCK_HA(ha, flags);
987
988     ret_val = FALSE;
989     if (ha->scratch_busy) {
990         if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size)
991             ret_val = TRUE;
992     }
993     GDTH_UNLOCK_HA(ha, flags);
994     return ret_val;
995 }
996 #endif
997
998 static void gdth_wait_completion(int hanum, int busnum, int id)
999 {
1000     gdth_ha_str *ha;
1001     ulong flags;
1002     int i;
1003     Scsi_Cmnd *scp;
1004     unchar b, t;
1005
1006     ha = HADATA(gdth_ctr_tab[hanum]);
1007     GDTH_LOCK_HA(ha, flags);
1008
1009     for (i = 0; i < GDTH_MAXCMDS; ++i) {
1010         scp = ha->cmd_tab[i].cmnd;
1011 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1012         b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
1013         t = scp->device->id;
1014 #else
1015         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1016         t = scp->target;
1017 #endif
1018         if (!SPECIAL_SCP(scp) && t == (unchar)id && 
1019             b == (unchar)busnum) {
1020             scp->SCp.have_data_in = 0;
1021             GDTH_UNLOCK_HA(ha, flags);
1022             while (!scp->SCp.have_data_in)
1023                 barrier();
1024 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1025             GDTH_LOCK_SCSI_DONE(scp->device->host, flags);
1026             scp->scsi_done(scp);
1027             GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags);
1028 #else
1029             GDTH_LOCK_SCSI_DONE(flags);
1030             scp->scsi_done(scp);
1031             GDTH_UNLOCK_SCSI_DONE(flags);
1032 #endif
1033         GDTH_LOCK_HA(ha, flags);
1034         }
1035     }
1036     GDTH_UNLOCK_HA(ha, flags);
1037 }
1038
1039 static void gdth_stop_timeout(int hanum, int busnum, int id)
1040 {
1041     gdth_ha_str *ha;
1042     ulong flags;
1043     Scsi_Cmnd *scp;
1044     unchar b, t;
1045
1046     ha = HADATA(gdth_ctr_tab[hanum]);
1047     GDTH_LOCK_HA(ha, flags);
1048
1049     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
1050 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1051         b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
1052         t = scp->device->id;
1053 #else
1054         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1055         t = scp->target;
1056 #endif
1057         if (t == (unchar)id && b == (unchar)busnum) {
1058             TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
1059             scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
1060         }
1061     }
1062     GDTH_UNLOCK_HA(ha, flags);
1063 }
1064
1065 static void gdth_start_timeout(int hanum, int busnum, int id)
1066 {
1067     gdth_ha_str *ha;
1068     ulong flags;
1069     Scsi_Cmnd *scp;
1070     unchar b, t;
1071
1072     ha = HADATA(gdth_ctr_tab[hanum]);
1073     GDTH_LOCK_HA(ha, flags);
1074
1075     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
1076 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1077         b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
1078         t = scp->device->id;
1079 #else
1080         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1081         t = scp->target;
1082 #endif
1083         if (t == (unchar)id && b == (unchar)busnum) {
1084             TRACE2(("gdth_start_timeout(): update_timeout()\n"));
1085             gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
1086         }
1087     }
1088     GDTH_UNLOCK_HA(ha, flags);
1089 }
1090
1091 static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
1092 {
1093     int oldto;
1094
1095     oldto = scp->timeout_per_command;
1096     scp->timeout_per_command = timeout;
1097
1098     if (timeout == 0) {
1099         del_timer(&scp->eh_timeout);
1100         scp->eh_timeout.data = (unsigned long) NULL;
1101         scp->eh_timeout.expires = 0;
1102     } else {
1103         if (scp->eh_timeout.data != (unsigned long) NULL) 
1104             del_timer(&scp->eh_timeout);
1105         scp->eh_timeout.data = (unsigned long) scp;
1106         scp->eh_timeout.expires = jiffies + timeout;
1107         add_timer(&scp->eh_timeout);
1108     }
1109
1110     return oldto;
1111 }