make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / drivers / scsi / gdth_proc.c
1 /* gdth_proc.c 
2  * $Id: gdth_proc.c,v 1.1.1.1 2005/04/11 02:50:36 jack Exp $
3  */
4
5 #include "gdth_ioctl.h"
6 #if LINUX_VERSION_CODE >= 0x020407
7 #include <linux/completion.h>
8 #endif
9
10 int gdth_proc_info(char *buffer,char **start,off_t offset,int length,   
11                    int hostno,int inout)
12 {
13     int hanum,busnum,i;
14
15     TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n",
16             length,hostno,(int)offset,inout));
17
18     for (i=0; i<gdth_ctr_vcount; ++i) {
19         if (gdth_ctr_vtab[i]->host_no == hostno)
20             break;
21     }
22     if (i==gdth_ctr_vcount)
23         return(-EINVAL);
24
25     hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
26     busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
27
28     if (inout)
29         return(gdth_set_info(buffer,length,i,hanum,busnum));
30     else
31         return(gdth_get_info(buffer,start,offset,length,i,hanum,busnum));
32 }
33
34 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
35 {
36     int             ret_val;
37 #if LINUX_VERSION_CODE >= 0x020322
38     Scsi_Cmnd       *scp;
39     Scsi_Device     *sdev;
40 #else
41     Scsi_Cmnd       scp;
42     Scsi_Device     sdev;
43 #endif
44     gdth_iowr_str   *piowr;
45
46     TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
47     piowr = (gdth_iowr_str *)buffer;
48
49 #if LINUX_VERSION_CODE >= 0x020322
50     sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
51     scp  = scsi_allocate_device(sdev, 1, FALSE);
52     if (!scp)
53         return -ENOMEM;
54     scp->cmd_len = 12;
55     scp->use_sg = 0;
56 #else
57     memset(&sdev,0,sizeof(Scsi_Device));
58     memset(&scp, 0,sizeof(Scsi_Cmnd));
59     sdev.host = scp.host = gdth_ctr_vtab[vh];
60     sdev.id = scp.target = sdev.host->this_id;
61     scp.device = &sdev;
62 #endif
63
64     if (length >= 4) {
65         if (strncmp(buffer,"gdth",4) == 0) {
66             buffer += 5;
67             length -= 5;
68             ret_val = gdth_set_asc_info( buffer, length, hanum, scp );
69         } else if (piowr->magic == GDTIOCTL_MAGIC) {
70             ret_val = gdth_set_bin_info( buffer, length, hanum, scp );
71         } else {
72             printk("GDT: Wrong signature %x (%x required)!\n",
73                    piowr->magic, GDTIOCTL_MAGIC);
74             if (piowr->magic > GDTIOCTL_MAGIC)
75                 printk("GDT: Please update your driver.\n");
76             else
77                 printk("GDT: Please update your tool.\n");
78             ret_val = -EINVAL;
79         }
80     } else {
81         ret_val = -EINVAL;
82     }
83 #if LINUX_VERSION_CODE >= 0x020322
84     scsi_release_command(scp);
85     scsi_free_host_dev(sdev);
86 #endif
87     return ret_val;
88 }
89          
90 #if LINUX_VERSION_CODE >= 0x020322
91 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
92 #else
93 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
94 #endif
95 {
96     int             orig_length, drive, wb_mode;
97     int             i, found;
98     gdth_ha_str     *ha;
99     gdth_cmd_str    gdtcmd;
100     gdth_cpar_str   *pcpar;
101
102     char            cmnd[MAX_COMMAND_SIZE];
103     memset(cmnd, 0xff, 12);
104     memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
105
106     TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
107     ha = HADATA(gdth_ctr_tab[hanum]);
108     orig_length = length + 5;
109     drive = -1;
110     wb_mode = 0;
111     found = FALSE;
112
113     if (length >= 5 && strncmp(buffer,"flush",5)==0) {
114         buffer += 6;
115         length -= 6;
116         if (length && *buffer>='0' && *buffer<='9') {
117             drive = (int)(*buffer-'0');
118             ++buffer; --length;
119             if (length && *buffer>='0' && *buffer<='9') {
120                 drive = drive*10 + (int)(*buffer-'0');
121                 ++buffer; --length;
122             }
123             printk("GDT: Flushing host drive %d .. ",drive);
124         } else {
125             printk("GDT: Flushing all host drives .. ");
126         }
127         for (i = 0; i < MAX_HDRIVES; ++i) {
128             if (ha->hdr[i].present) {
129                 if (drive != -1 && i != drive)
130                     continue;
131                 found = TRUE;
132                 gdtcmd.Service = CACHESERVICE;
133                 gdtcmd.OpCode = GDT_FLUSH;
134                 gdtcmd.u.cache.DeviceNo = i;
135                 gdtcmd.u.cache.BlockNo = 1;
136 #if LINUX_VERSION_CODE >= 0x020322
137                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
138 #else
139                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
140 #endif
141             }
142         }
143         if (!found)
144             printk("\nNo host drive found !\n");
145         else
146             printk("Done.\n");
147         return(orig_length);
148     }
149
150     if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
151         buffer += 8;
152         length -= 8;
153         printk("GDT: Disabling write back permanently .. ");
154         wb_mode = 1;
155     } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
156         buffer += 7;
157         length -= 7;
158         printk("GDT: Enabling write back permanently .. ");
159         wb_mode = 2;
160     } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
161         buffer += 7;
162         length -= 7;
163         printk("GDT: Disabling write back commands .. ");
164         if (ha->cache_feat & GDT_WR_THROUGH) {
165             gdth_write_through = TRUE;
166             printk("Done.\n");
167         } else {
168             printk("Not supported !\n");
169         }
170         return(orig_length);
171     } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
172         buffer += 6;
173         length -= 6;
174         printk("GDT: Enabling write back commands .. ");
175         gdth_write_through = FALSE;
176         printk("Done.\n");
177         return(orig_length);
178     }
179
180     if (wb_mode) {
181         if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE))
182             return(-EBUSY);
183         pcpar = (gdth_cpar_str *)ha->pscratch;
184         memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
185         gdtcmd.Service = CACHESERVICE;
186         gdtcmd.OpCode = GDT_IOCTL;
187         gdtcmd.u.ioctl.p_param = virt_to_bus(pcpar);
188         gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
189         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
190         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
191         pcpar->write_back = wb_mode==1 ? 0:1;
192 #if LINUX_VERSION_CODE >= 0x020322
193         gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
194 #else
195         gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
196 #endif
197         gdth_ioctl_free(hanum, ha->pscratch);
198         printk("Done.\n");
199         return(orig_length);
200     }
201
202     printk("GDT: Unknown command: %s  Length: %d\n",buffer,length);
203     return(-EINVAL);
204 }
205
206 #if LINUX_VERSION_CODE >= 0x020322
207 static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
208 #else
209 static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
210 #endif
211 {
212     unchar          i, j;
213     ushort          k, hdr_cnt, status;
214     gdth_ha_str     *ha;
215     gdth_iowr_str   *piowr;
216     gdth_iord_str   *piord;
217     gdth_cmd_str    *pcmd;
218     gdth_evt_str    *pevt;
219     ulong32         *ppadd, add_size, *ppadd2, add_size2, info;
220     ulong           flags;
221     gdth_cmd_str    gdtcmd;
222     int             drv_cyls, drv_hds, drv_secs;
223  
224     char            cmnd[MAX_COMMAND_SIZE];   
225     memset(cmnd, 0xff, 12);
226     memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
227
228     TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
229     ha = HADATA(gdth_ctr_tab[hanum]);
230     piowr = (gdth_iowr_str *)buffer;
231     piord = NULL;
232     pcmd = NULL;
233     ppadd = ppadd2 = NULL;
234     add_size = add_size2 = 0;
235
236     if (length < GDTOFFSOF(gdth_iowr_str,iu))
237         return(-EINVAL);
238
239     switch (piowr->ioctl) {
240       case GDTIOCTL_GENERAL:
241         if (length < GDTOFFSOF(gdth_iowr_str,iu.general.data[0]))
242             return(-EINVAL);
243         pcmd = (gdth_cmd_str *)piowr->iu.general.command;
244         pcmd->Service = piowr->service;
245         if (pcmd->OpCode == GDT_IOCTL) {
246             ppadd = &pcmd->u.ioctl.p_param;
247             add_size = pcmd->u.ioctl.param_size;
248         } else if (piowr->service == CACHESERVICE) {
249             add_size = pcmd->u.cache.BlockCnt * SECTOR_SIZE;
250             if (ha->cache_feat & SCATTER_GATHER) {
251                 ppadd = &pcmd->u.cache.sg_lst[0].sg_ptr;
252                 pcmd->u.cache.DestAddr = 0xffffffff;
253                 pcmd->u.cache.sg_lst[0].sg_len = add_size;
254                 pcmd->u.cache.sg_canz = 1;
255             } else {
256                 ppadd = &pcmd->u.cache.DestAddr;
257                 pcmd->u.cache.sg_canz = 0;
258             }
259         } else if (piowr->service == SCSIRAWSERVICE) {
260             add_size = pcmd->u.raw.sdlen;
261             add_size2 = pcmd->u.raw.sense_len;
262             if (ha->raw_feat & SCATTER_GATHER) {
263                 ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr;
264                 pcmd->u.raw.sdata = 0xffffffff;
265                 pcmd->u.raw.sg_lst[0].sg_len = add_size;
266                 pcmd->u.raw.sg_ranz = 1;
267             } else {
268                 ppadd = &pcmd->u.raw.sdata;
269                 pcmd->u.raw.sg_ranz = 0;
270             }
271             ppadd2 = &pcmd->u.raw.sense_data;
272         } else {
273             return(-EINVAL);
274         }
275         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str)+add_size+add_size2,
276                                TRUE ))
277             return(-EBUSY);
278         piord = (gdth_iord_str *)ha->pscratch;
279
280         piord->size = sizeof(gdth_iord_str) + add_size + add_size2;
281         if (add_size > 0) {
282             memcpy(piord->iu.general.data, piowr->iu.general.data, add_size);
283             *ppadd = virt_to_bus(piord->iu.general.data);
284         }
285         if (add_size2 > 0) {
286             memcpy(piord->iu.general.data+add_size, piowr->iu.general.data, add_size2);
287             *ppadd2 = virt_to_bus(piord->iu.general.data+add_size);
288         }
289         /* do IOCTL */
290 #if LINUX_VERSION_CODE >= 0x020322
291         gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
292         piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
293 #else
294         gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
295         piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
296 #endif
297         break;
298
299       case GDTIOCTL_DRVERS:
300         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
301             return(-EBUSY);
302         piord = (gdth_iord_str *)ha->pscratch;
303         piord->size = sizeof(gdth_iord_str);
304         piord->status = S_OK;
305         piord->iu.drvers.version = (GDTH_VERSION<<8) | GDTH_SUBVERSION;
306         break;
307
308       case GDTIOCTL_CTRTYPE:
309         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
310             return(-EBUSY);
311         piord = (gdth_iord_str *)ha->pscratch;
312         piord->size = sizeof(gdth_iord_str);
313         piord->status = S_OK;
314         if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
315             piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 0x10);
316         } else {
317             if (ha->type != GDT_PCIMPR) {
318                 piord->iu.ctrtype.type = (unchar)((ha->stype<<4) + 6);
319             } else {
320                 piord->iu.ctrtype.type = 
321                     (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe);
322                 if (ha->stype >= 0x300)
323                     piord->iu.ctrtype.ext_type = 0x6000 | ha->subdevice_id;
324                 else 
325                     piord->iu.ctrtype.ext_type = 0x6000 | ha->stype;
326             }
327             piord->iu.ctrtype.device_id = ha->stype;
328             piord->iu.ctrtype.sub_device_id = ha->subdevice_id;
329         }
330         piord->iu.ctrtype.info = ha->brd_phys;
331         piord->iu.ctrtype.oem_id = ha->oem_id;
332         break;
333
334       case GDTIOCTL_CTRCNT:
335         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
336             return(-EBUSY);
337         piord = (gdth_iord_str *)ha->pscratch;
338         piord->size = sizeof(gdth_iord_str);
339         piord->status = S_OK;
340         piord->iu.ctrcnt.count = (ushort)gdth_ctr_count;
341         break;
342
343       case GDTIOCTL_OSVERS:
344         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
345             return(-EBUSY);
346         piord = (gdth_iord_str *)ha->pscratch;
347         piord->size = sizeof(gdth_iord_str);
348         piord->status = S_OK;
349         piord->iu.osvers.version = (unchar)(LINUX_VERSION_CODE >> 16);
350         piord->iu.osvers.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
351         piord->iu.osvers.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
352         break;
353
354       case GDTIOCTL_LOCKDRV:
355         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
356             return(-EBUSY);
357         piord = (gdth_iord_str *)ha->pscratch;
358         for (i = 0; i < piowr->iu.lockdrv.drive_cnt; ++i) {
359             j = piowr->iu.lockdrv.drives[i];
360             if (j >= MAX_HDRIVES || !ha->hdr[j].present) 
361                 continue;
362             if (piowr->iu.lockdrv.lock) {
363                 GDTH_LOCK_HA(ha, flags);
364                 ha->hdr[j].lock = 1;
365                 GDTH_UNLOCK_HA(ha, flags);
366                 gdth_wait_completion( hanum, ha->bus_cnt, j );
367                 gdth_stop_timeout( hanum, ha->bus_cnt, j );
368             } else {
369                 GDTH_LOCK_HA(ha, flags);
370                 ha->hdr[j].lock = 0;
371                 GDTH_UNLOCK_HA(ha, flags);
372                 gdth_start_timeout( hanum, ha->bus_cnt, j );
373                 gdth_next( hanum );
374             }
375         }
376         piord->size = sizeof(gdth_iord_str);
377         piord->status = S_OK;
378         break;
379
380       case GDTIOCTL_LOCKCHN:
381         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
382             return(-EBUSY);
383         i = piowr->iu.lockchn.channel;
384         if (i < ha->bus_cnt) {
385             if (piowr->iu.lockchn.lock) {
386                 GDTH_LOCK_HA(ha, flags);
387                 ha->raw[i].lock = 1;
388                 GDTH_UNLOCK_HA(ha, flags);
389                 for (j = 0; j < ha->tid_cnt; ++j) {
390                     gdth_wait_completion( hanum, i, j );
391                     gdth_stop_timeout( hanum, i, j );
392                 }
393             } else {
394                 GDTH_LOCK_HA(ha, flags);
395                 ha->raw[i].lock = 0;
396                 GDTH_UNLOCK_HA(ha, flags);
397                 for (j = 0; j < ha->tid_cnt; ++j) {
398                     gdth_start_timeout( hanum, i, j );
399                     gdth_next( hanum );
400                 }
401             }
402         }
403         piord = (gdth_iord_str *)ha->pscratch;
404         piord->size = sizeof(gdth_iord_str);
405         piord->status = S_OK;
406         break;
407
408       case GDTIOCTL_EVENT:
409         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
410             return(-EBUSY);
411         piord = (gdth_iord_str *)ha->pscratch;
412         if (piowr->iu.event.erase == 0xff) {
413             pevt = (gdth_evt_str *)piowr->iu.event.evt;
414             if (pevt->event_source == ES_TEST) 
415                 pevt->event_data.size = sizeof(pevt->event_data.eu.test);
416             else if (pevt->event_source == ES_DRIVER) 
417                 pevt->event_data.size = sizeof(pevt->event_data.eu.driver);
418             else if (pevt->event_source == ES_SYNC) 
419                 pevt->event_data.size = sizeof(pevt->event_data.eu.sync);
420             else {
421                 pevt->event_data.size = sizeof(pevt->event_data.eu.async);
422                 gdth_log_event(&pevt->event_data, NULL);
423             }
424             GDTH_LOCK_HA(ha, flags);
425             gdth_store_event(ha, pevt->event_source, pevt->event_idx,
426                              &pevt->event_data);
427             GDTH_UNLOCK_HA(ha, flags);
428         } else if (piowr->iu.event.erase == 0xfe) {
429             gdth_clear_events();
430         } else if (piowr->iu.event.erase == 0) {
431             piord->iu.event.handle = 
432                 gdth_read_event(ha,piowr->iu.event.handle,
433                                 (gdth_evt_str *)piord->iu.event.evt);
434         } else {
435             piord->iu.event.handle = piowr->iu.event.handle;
436             gdth_readapp_event(ha, (unchar)piowr->iu.event.erase,
437                                (gdth_evt_str *)piord->iu.event.evt);
438         }
439         piord->size = sizeof(gdth_iord_str);
440         piord->status = S_OK;
441         break;
442
443       case GDTIOCTL_SCSI:
444         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
445             return(-EBUSY);
446         piord = (gdth_iord_str *)ha->pscratch;
447         piord->size = sizeof(gdth_iord_str);
448         memcpy(cmnd, piowr->iu.scsi.cmd, 12);
449 #if LINUX_VERSION_CODE >= 0x020322
450         scp->target = piowr->iu.scsi.target;
451         scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
452         scp->cmd_len = piowr->iu.scsi.cmd_len;
453         gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout);
454         piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
455 #else
456         scp.target = piowr->iu.scsi.target;
457         scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
458         scp.cmd_len = piowr->iu.scsi.cmd_len;
459         gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
460         piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
461 #endif
462         break;
463
464       case GDTIOCTL_RESET_BUS:
465         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
466             return(-EBUSY);
467         piord = (gdth_iord_str *)ha->pscratch;
468         piord->size = sizeof(gdth_iord_str);
469 #if LINUX_VERSION_CODE >= 0x020322
470         scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
471         piord->status = (ulong32)gdth_eh_bus_reset( scp );
472         if (piord->status == SUCCESS)
473             piord->status = S_OK;
474         else
475             piord->status = S_GENERR;
476 #elif LINUX_VERSION_CODE >= 0x02015F
477         scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus;
478         piord->status = (ulong32)gdth_eh_bus_reset( &scp );
479         if (piord->status == SUCCESS)
480             piord->status = S_OK;
481         else
482             piord->status = S_GENERR;
483 #else
484         piord->status = S_OK;
485 #endif
486         break;
487
488       case GDTIOCTL_HDRLIST:
489         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
490             return(-EBUSY);
491         piord = (gdth_iord_str *)ha->pscratch;
492         piord->size = sizeof(gdth_iord_str);
493         piord->status = S_OK;
494         for (i = 0; i < MAX_HDRIVES; ++i) {
495             if (ha->hdr[i].present) {
496                 piord->iu.hdr_list[i].bus = ha->virt_bus;
497                 piord->iu.hdr_list[i].target = i;
498                 piord->iu.hdr_list[i].lun = 0;
499                 piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
500                 if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) {  
501                     gdtcmd.Service = CACHESERVICE;
502                     gdtcmd.OpCode = GDT_CLUST_INFO;
503                     gdtcmd.u.cache.DeviceNo = i;
504 #if LINUX_VERSION_CODE >= 0x020322
505                     gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
506                     if (scp->SCp.Status == S_OK)
507                         piord->iu.hdr_list[i].cluster_type = 
508                             (unchar)scp->SCp.Message;
509 #else
510                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
511                     if (scp.SCp.Status == S_OK)
512                         piord->iu.hdr_list[i].cluster_type = 
513                             (unchar)scp.SCp.Message;
514 #endif
515                 }
516             } else {
517                 piord->iu.hdr_list[i].bus = 0xff;
518             }
519         }
520         break;
521
522       case GDTIOCTL_RESCAN:
523         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
524             return(-EBUSY);
525         piord = (gdth_iord_str *)ha->pscratch;
526         piord->size = sizeof(gdth_iord_str);
527         piord->status = S_OK;
528         if (piowr->iu.rescan.flag == 0) {
529             /* old method: scan all host drives 
530                re-initialize cache service to get host drive count
531             */
532             gdtcmd.Service = CACHESERVICE;
533             gdtcmd.OpCode = GDT_INIT;
534             gdtcmd.u.cache.DeviceNo = LINUX_OS;
535 #if LINUX_VERSION_CODE >= 0x020322
536             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
537             status = (ushort)scp->SCp.Status; 
538             info = (ulong32)scp->SCp.Message;
539 #else
540             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
541             status = (ushort)scp.SCp.Status;
542             info = (ulong32)scp.SCp.Message;
543 #endif
544             if (status != S_OK)
545                 break;
546             k = 0;
547             hdr_cnt = (ushort)info;
548         } else {
549             k = piowr->iu.rescan.hdr_no;
550             hdr_cnt = k + 1;
551         }
552         if (hdr_cnt > MAX_HDRIVES)
553             hdr_cnt = MAX_HDRIVES;
554         /* scanning for host drives */
555         for (; k < hdr_cnt; ++k) {
556             /* info about host drive */
557             gdtcmd.Service = CACHESERVICE;
558             gdtcmd.OpCode = GDT_INFO;
559             gdtcmd.u.cache.DeviceNo = k;
560 #if LINUX_VERSION_CODE >= 0x020322
561             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
562             status = (ushort)scp->SCp.Status; 
563             info = (ulong32)scp->SCp.Message;
564 #else
565             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
566             status = (ushort)scp.SCp.Status;
567             info = (ulong32)scp.SCp.Message;
568 #endif
569             GDTH_LOCK_HA(ha, flags);
570             piord->iu.hdr_list[k].bus = ha->virt_bus;
571             piord->iu.hdr_list[k].target = k;
572             piord->iu.hdr_list[k].lun = 0;
573             if (status != S_OK) {
574                 ha->hdr[k].present = FALSE;
575             } else {
576                 ha->hdr[k].present = TRUE;
577                 ha->hdr[k].size = info;
578                 /* evaluate mapping (sectors per head, heads per cylinder) */
579                 ha->hdr[k].size &= ~SECS32;
580                 gdth_eval_mapping(ha->hdr[k].size,&drv_cyls,&drv_hds,&drv_secs);
581                 ha->hdr[k].heads = (unchar)drv_hds;
582                 ha->hdr[k].secs = (unchar)drv_secs;
583                 /* round size */
584                 ha->hdr[k].size = drv_cyls * drv_hds * drv_secs;
585             }
586             GDTH_UNLOCK_HA(ha, flags);
587             if (status != S_OK)
588                 continue;       /* next host drive */
589
590             /* devtype, cluster info, R/W attributes */
591             gdtcmd.Service = CACHESERVICE;
592             gdtcmd.OpCode = GDT_DEVTYPE;
593             gdtcmd.u.cache.DeviceNo = k;
594 #if LINUX_VERSION_CODE >= 0x020322
595             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
596             status = (ushort)scp->SCp.Status; 
597             info = (ulong32)scp->SCp.Message;
598 #else
599             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
600             status = (ushort)scp.SCp.Status;
601             info = (ulong32)scp.SCp.Message;
602 #endif
603             GDTH_LOCK_HA(ha, flags);
604             ha->hdr[k].devtype = 0;
605             if (status == S_OK)
606                 ha->hdr[k].devtype = (ushort)info;
607             GDTH_UNLOCK_HA(ha, flags);
608
609             gdtcmd.Service = CACHESERVICE;
610             gdtcmd.OpCode = GDT_CLUST_INFO;
611             gdtcmd.u.cache.DeviceNo = k;
612 #if LINUX_VERSION_CODE >= 0x020322
613             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
614             status = (ushort)scp->SCp.Status; 
615             info = (ulong32)scp->SCp.Message;
616 #else
617             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
618             status = (ushort)scp.SCp.Status;
619             info = (ulong32)scp.SCp.Message;
620 #endif
621             GDTH_LOCK_HA(ha, flags);
622             ha->hdr[k].cluster_type = 0;
623             if (status == S_OK && !shared_access)
624                 ha->hdr[k].cluster_type = (ushort)info;
625             GDTH_UNLOCK_HA(ha, flags);
626             piord->iu.hdr_list[k].cluster_type = ha->hdr[k].cluster_type;
627
628             gdtcmd.Service = CACHESERVICE;
629             gdtcmd.OpCode = GDT_RW_ATTRIBS;
630             gdtcmd.u.cache.DeviceNo = k;
631 #if LINUX_VERSION_CODE >= 0x020322
632             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
633             status = (ushort)scp->SCp.Status; 
634             info = (ulong32)scp->SCp.Message;
635 #else
636             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
637             status = (ushort)scp.SCp.Status;
638             info = (ulong32)scp.SCp.Message;
639 #endif
640             GDTH_LOCK_HA(ha, flags);
641             ha->hdr[k].rw_attribs = 0;
642             if (status == S_OK)
643                 ha->hdr[k].rw_attribs = (ushort)info;
644             GDTH_UNLOCK_HA(ha, flags);
645         }
646         break;
647
648       case GDTIOCTL_RESET_DRV:
649         if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE ))
650             return(-EBUSY);
651         piord = (gdth_iord_str *)ha->pscratch;
652         piord->size = sizeof(gdth_iord_str);
653         piord->status = S_OK;
654         i = piowr->iu.scsi.target;
655         if (ha->hdr[i].present) {
656             gdtcmd.Service = CACHESERVICE;
657             gdtcmd.OpCode = GDT_CLUST_RESET;
658             gdtcmd.u.cache.DeviceNo = i;
659 #if LINUX_VERSION_CODE >= 0x020322
660             gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
661             piord->status = (scp->SCp.Message<<16)|scp->SCp.Status;
662 #else
663             gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
664             piord->status = (scp.SCp.Message<<16)|scp.SCp.Status;
665 #endif
666         }
667         break;
668
669       default:
670         return(-EINVAL);
671     }
672     return length;
673 }
674
675 static int gdth_get_info(char *buffer,char **start,off_t offset,
676                          int length,int vh,int hanum,int busnum)
677 {
678     int size = 0,len = 0;
679     off_t begin = 0,pos = 0;
680     gdth_ha_str *ha;
681     gdth_iord_str *piord;
682     int id, i, j, k, sec, flag;
683     int no_mdrv = 0, drv_no, is_mirr;
684     ulong32 cnt;
685
686     gdth_cmd_str gdtcmd;
687     gdth_evt_str estr;
688 #if LINUX_VERSION_CODE >= 0x020322
689     Scsi_Cmnd *scp;
690     Scsi_Device *sdev;
691 #else
692     Scsi_Cmnd scp;
693     Scsi_Device sdev;
694 #endif
695     char hrec[161];
696     struct timeval tv;
697
698     char *buf;
699     gdth_dskstat_str *pds;
700     gdth_diskinfo_str *pdi;
701     gdth_arrayinf_str *pai;
702     gdth_defcnt_str *pdef;
703     gdth_cdrinfo_str *pcdi;
704     gdth_hget_str *phg;
705
706     char cmnd[MAX_COMMAND_SIZE];
707     memset(cmnd, 0xff, 12);
708     memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
709
710     TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
711     ha = HADATA(gdth_ctr_tab[hanum]);
712
713 #if LINUX_VERSION_CODE >= 0x020322
714     sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
715     scp  = scsi_allocate_device(sdev, 1, FALSE);
716     if (!scp)
717         return -ENOMEM;
718     scp->cmd_len = 12;
719     scp->use_sg = 0;
720 #else
721     memset(&sdev,0,sizeof(Scsi_Device));
722     memset(&scp, 0,sizeof(Scsi_Cmnd));
723     sdev.host = scp.host = gdth_ctr_vtab[vh];
724     sdev.id = scp.target = sdev.host->this_id;
725     scp.device = &sdev;
726 #endif
727
728     /* ioctl from tool? */
729     if (!gdth_ioctl_check_bin(hanum, (ushort)length)) {
730         /* request is i.e. "cat /proc/scsi/gdth/0" */ 
731         /* format: %-15s\t%-10s\t%-15s\t%s */
732         /* driver parameters */
733         size = sprintf(buffer+len,"Driver Parameters:\n");
734         len += size;  pos = begin + len;
735         if (reserve_list[0] == 0xff)
736             strcpy(hrec, "--");
737         else {
738             sprintf(hrec, "%d", reserve_list[0]);
739             for (i = 1;  i < MAX_RES_ARGS; i++) {
740                 if (reserve_list[i] == 0xff) 
741                     break;
742                 sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
743             }
744         }
745         size = sprintf(buffer+len,
746                        " reserve_mode: \t%d         \treserve_list:  \t%s\n",
747                        reserve_mode, hrec);
748         len += size;  pos = begin + len;
749         size = sprintf(buffer+len,
750                        " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
751                        max_ids, hdr_channel);
752         len += size;  pos = begin + len;
753
754         /* controller information */
755         size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
756         len += size;  pos = begin + len;
757         if (virt_ctr)
758             sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
759         else
760             strcpy(hrec, ha->binfo.type_string);
761         size = sprintf(buffer+len,
762                        " Number:       \t%d         \tName:          \t%s\n",
763                        hanum, hrec);
764         len += size;  pos = begin + len;
765
766         if (ha->more_proc)
767             sprintf(hrec, "%d.%02d.%02d-%c%03X", 
768                     (unchar)(ha->binfo.upd_fw_ver>>24),
769                     (unchar)(ha->binfo.upd_fw_ver>>16),
770                     (unchar)(ha->binfo.upd_fw_ver),
771                     ha->bfeat.raid ? 'R':'N',
772                     ha->binfo.upd_revision);
773         else
774             sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
775                     (unchar)(ha->cpar.version));
776
777         size = sprintf(buffer+len,
778                        " Driver Ver.:  \t%-10s\tFirmware Ver.: \t%s\n",
779                        GDTH_VERSION_STR, hrec);
780         len += size;  pos = begin + len;
781  
782         if (pos < offset) {
783             len = 0;
784             begin = pos;
785         }
786         if (pos > offset + length)
787             goto stop_output;
788
789         if (ha->more_proc) {
790             /* more information: 1. about controller */
791             size = sprintf(buffer+len,
792                            " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
793                            ha->binfo.ser_no, ha->binfo.memsize / 1024);
794             len += size;  pos = begin + len;
795
796             /* 2. about physical devices */
797             size = sprintf(buffer+len,"\nPhysical Devices:");
798             len += size;  pos = begin + len;
799             flag = FALSE;
800             
801             buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE);
802             if (!buf) 
803                 goto stop_output;
804             for (i = 0; i < ha->bus_cnt; ++i) {
805                 /* 2.a statistics (and retries/reassigns) */
806                 TRACE2(("pdr_statistics() chn %d\n",i));                
807                 pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
808                 gdtcmd.Service = CACHESERVICE;
809                 gdtcmd.OpCode = GDT_IOCTL;
810                 gdtcmd.u.ioctl.p_param = virt_to_bus(pds);
811                 gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4;
812                 gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
813                 gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
814                 pds->bid = ha->raw[i].local_no;
815                 pds->first = 0;
816                 pds->entries = ha->raw[i].pdev_cnt;
817                 cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
818                     sizeof(pds->list[0]);
819                 if (pds->entries > cnt)
820                     pds->entries = cnt;
821 #if LINUX_VERSION_CODE >= 0x020322
822                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
823                 if (scp->SCp.Status != S_OK) 
824 #else
825                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
826                 if (scp.SCp.Status != S_OK) 
827 #endif
828                 { 
829                     pds->count = 0;
830                 }
831
832                 /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
833                 for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
834                     /* 2.b drive info */
835                     TRACE2(("scsi_drv_info() chn %d dev %d\n",
836                         i, ha->raw[i].id_list[j]));             
837                     pdi = (gdth_diskinfo_str *)buf;
838                     gdtcmd.Service = CACHESERVICE;
839                     gdtcmd.OpCode = GDT_IOCTL;
840                     gdtcmd.u.ioctl.p_param = virt_to_bus(pdi);
841                     gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str);
842                     gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
843                     gdtcmd.u.ioctl.channel = 
844                         ha->raw[i].address | ha->raw[i].id_list[j];
845 #if LINUX_VERSION_CODE >= 0x020322
846                     gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
847                     if (scp->SCp.Status == S_OK) 
848 #else
849                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
850                     if (scp.SCp.Status == S_OK) 
851 #endif
852                     {
853                         strncpy(hrec,pdi->vendor,8);
854                         strncpy(hrec+8,pdi->product,16);
855                         strncpy(hrec+24,pdi->revision,4);
856                         hrec[28] = 0;
857                         size = sprintf(buffer+len,
858                                        "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
859                                        'A'+i,pdi->target_id,pdi->lun,hrec);
860                         len += size;  pos = begin + len;
861                         flag = TRUE;
862                         pdi->no_ldrive &= 0xffff;
863                         if (pdi->no_ldrive == 0xffff)
864                             strcpy(hrec,"--");
865                         else
866                             sprintf(hrec,"%d",pdi->no_ldrive);
867                         size = sprintf(buffer+len,
868                                        " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
869                                        pdi->blkcnt/(1024*1024/pdi->blksize),
870                                        hrec);
871                         len += size;  pos = begin + len;
872                     } else {
873                         pdi->devtype = 0xff;
874                     }
875                     
876                     if (pdi->devtype == 0) {
877                         /* search retries/reassigns */
878                         for (k = 0; k < pds->count; ++k) {
879                             if (pds->list[k].tid == pdi->target_id &&
880                                 pds->list[k].lun == pdi->lun) {
881                                 size = sprintf(buffer+len,
882                                                " Retries:      \t%-6d    \tReassigns:     \t%d\n",
883                                                pds->list[k].retries,
884                                                pds->list[k].reassigns);
885                                 len += size;  pos = begin + len;
886                                 break;
887                             }
888                         }
889                         /* 2.c grown defects */
890                         TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
891                                 i, ha->raw[i].id_list[j]));             
892                         pdef = (gdth_defcnt_str *)buf;
893                         gdtcmd.Service = CACHESERVICE;
894                         gdtcmd.OpCode = GDT_IOCTL;
895                         gdtcmd.u.ioctl.p_param = virt_to_bus(pdef);
896                         gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str);
897                         gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
898                         gdtcmd.u.ioctl.channel = 
899                             ha->raw[i].address | ha->raw[i].id_list[j];
900                         pdef->sddc_type = 0x08;
901 #if LINUX_VERSION_CODE >= 0x020322
902                         gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
903                         if (scp->SCp.Status == S_OK) 
904 #else
905                         gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
906                         if (scp.SCp.Status == S_OK) 
907 #endif
908                         {
909                             size = sprintf(buffer+len,
910                                            " Grown Defects:\t%d\n",
911                                            pdef->sddc_cnt);
912                             len += size;  pos = begin + len;
913                         }
914                     }
915                     if (pos < offset) {
916                         len = 0;
917                         begin = pos;
918                     }
919                     if (pos > offset + length)
920                         goto stop_output;
921                 }
922             }
923             gdth_ioctl_free(hanum, buf);
924
925             if (!flag) {
926                 size = sprintf(buffer+len, "\n --\n");
927                 len += size;  pos = begin + len;
928             }
929
930             /* 3. about logical drives */
931             size = sprintf(buffer+len,"\nLogical Drives:");
932             len += size;  pos = begin + len;
933             flag = FALSE;
934
935             buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE);
936             if (!buf) 
937                 goto stop_output;
938             for (i = 0; i < MAX_LDRIVES; ++i) {
939                 if (!ha->hdr[i].is_logdrv)
940                     continue;
941                 drv_no = i;
942                 j = k = 0;
943                 is_mirr = FALSE;
944                 do {
945                     /* 3.a log. drive info */
946                     TRACE2(("cache_drv_info() drive no %d\n",drv_no));
947                     pcdi = (gdth_cdrinfo_str *)buf;
948                     gdtcmd.Service = CACHESERVICE;
949                     gdtcmd.OpCode = GDT_IOCTL;
950                     gdtcmd.u.ioctl.p_param = virt_to_bus(pcdi);
951                     gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
952                     gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
953                     gdtcmd.u.ioctl.channel = drv_no;
954 #if LINUX_VERSION_CODE >= 0x020322
955                     gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
956                     if (scp->SCp.Status != S_OK)
957 #else
958                     gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
959                     if (scp.SCp.Status != S_OK)
960 #endif
961                     {
962                         break;
963                     }
964                     pcdi->ld_dtype >>= 16;
965                     j++;
966                     if (pcdi->ld_dtype > 2) {
967                         strcpy(hrec, "missing");
968                     } else if (pcdi->ld_error & 1) {
969                         strcpy(hrec, "fault");
970                     } else if (pcdi->ld_error & 2) {
971                         strcpy(hrec, "invalid");
972                         k++; j--;
973                     } else {
974                         strcpy(hrec, "ok");
975                     }
976                     
977                     if (drv_no == i) {
978                         size = sprintf(buffer+len,
979                                        "\n Number:       \t%-2d        \tStatus:        \t%s\n",
980                                        drv_no, hrec);
981                         len += size;  pos = begin + len;
982                         flag = TRUE;
983                         no_mdrv = pcdi->cd_ldcnt;
984                         if (no_mdrv > 1 || pcdi->ld_slave != -1) {
985                             is_mirr = TRUE;
986                             strcpy(hrec, "RAID-1");
987                         } else if (pcdi->ld_dtype == 0) {
988                             strcpy(hrec, "Disk");
989                         } else if (pcdi->ld_dtype == 1) {
990                             strcpy(hrec, "RAID-0");
991                         } else if (pcdi->ld_dtype == 2) {
992                             strcpy(hrec, "Chain");
993                         } else {
994                             strcpy(hrec, "???");
995                         }
996                         size = sprintf(buffer+len,
997                                        " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
998                                        pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
999                                        hrec);
1000                         len += size;  pos = begin + len;
1001                     } else {
1002                         size = sprintf(buffer+len,
1003                                        " Slave Number: \t%-2d        \tStatus:        \t%s\n",
1004                                        drv_no & 0x7fff, hrec);
1005                         len += size;  pos = begin + len;
1006                     }
1007                     drv_no = pcdi->ld_slave;
1008                     if (pos < offset) {
1009                         len = 0;
1010                         begin = pos;
1011                     }
1012                     if (pos > offset + length)
1013                         goto stop_output;
1014                 } while (drv_no != -1);
1015                 
1016                 if (is_mirr) {
1017                     size = sprintf(buffer+len,
1018                                    " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
1019                                    no_mdrv - j - k, k);
1020                     len += size;  pos = begin + len;
1021                 }
1022                 
1023                 if (!ha->hdr[i].is_arraydrv)
1024                     strcpy(hrec, "--");
1025                 else
1026                     sprintf(hrec, "%d", ha->hdr[i].master_no);
1027                 size = sprintf(buffer+len,
1028                                " To Array Drv.:\t%s\n", hrec);
1029                 len += size;  pos = begin + len;
1030                 if (pos < offset) {
1031                     len = 0;
1032                     begin = pos;
1033                 }
1034                 if (pos > offset + length)
1035                     goto stop_output;
1036             }       
1037             gdth_ioctl_free(hanum, buf);
1038         
1039             if (!flag) {
1040                 size = sprintf(buffer+len, "\n --\n");
1041                 len += size;  pos = begin + len;
1042             }   
1043
1044             /* 4. about array drives */
1045             size = sprintf(buffer+len,"\nArray Drives:");
1046             len += size;  pos = begin + len;
1047             flag = FALSE;
1048
1049             buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE);
1050             if (!buf) 
1051                 goto stop_output;
1052             for (i = 0; i < MAX_LDRIVES; ++i) {
1053                 if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
1054                     continue;
1055                 /* 4.a array drive info */
1056                 TRACE2(("array_info() drive no %d\n",i));
1057                 pai = (gdth_arrayinf_str *)buf;
1058                 gdtcmd.Service = CACHESERVICE;
1059                 gdtcmd.OpCode = GDT_IOCTL;
1060                 gdtcmd.u.ioctl.p_param = virt_to_bus(pai);
1061                 gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
1062                 gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
1063                 gdtcmd.u.ioctl.channel = i;
1064 #if LINUX_VERSION_CODE >= 0x020322
1065                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
1066                 if (scp->SCp.Status == S_OK) 
1067 #else
1068                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
1069                 if (scp.SCp.Status == S_OK) 
1070 #endif
1071                 {
1072                     if (pai->ai_state == 0)
1073                         strcpy(hrec, "idle");
1074                     else if (pai->ai_state == 2)
1075                         strcpy(hrec, "build");
1076                     else if (pai->ai_state == 4)
1077                         strcpy(hrec, "ready");
1078                     else if (pai->ai_state == 6)
1079                         strcpy(hrec, "fail");
1080                     else if (pai->ai_state == 8 || pai->ai_state == 10)
1081                         strcpy(hrec, "rebuild");
1082                     else
1083                         strcpy(hrec, "error");
1084                     if (pai->ai_ext_state & 0x10)
1085                         strcat(hrec, "/expand");
1086                     else if (pai->ai_ext_state & 0x1)
1087                         strcat(hrec, "/patch");
1088                     size = sprintf(buffer+len,
1089                                    "\n Number:       \t%-2d        \tStatus:        \t%s\n",
1090                                    i,hrec);
1091                     len += size;  pos = begin + len;
1092                     flag = TRUE;
1093
1094                     if (pai->ai_type == 0)
1095                         strcpy(hrec, "RAID-0");
1096                     else if (pai->ai_type == 4)
1097                         strcpy(hrec, "RAID-4");
1098                     else if (pai->ai_type == 5)
1099                         strcpy(hrec, "RAID-5");
1100                     else 
1101                         strcpy(hrec, "RAID-10");
1102                     size = sprintf(buffer+len,
1103                                    " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
1104                                    pai->ai_size/(1024*1024/pai->ai_secsize),
1105                                    hrec);
1106                     len += size;  pos = begin + len;
1107                     if (pos < offset) {
1108                         len = 0;
1109                         begin = pos;
1110                     }
1111                     if (pos > offset + length)
1112                         goto stop_output;
1113                 }
1114             }
1115             gdth_ioctl_free(hanum, buf);
1116         
1117             if (!flag) {
1118                 size = sprintf(buffer+len, "\n --\n");
1119                 len += size;  pos = begin + len;
1120             }
1121
1122             /* 5. about host drives */
1123             size = sprintf(buffer+len,"\nHost Drives:");
1124             len += size;  pos = begin + len;
1125             flag = FALSE;
1126
1127             buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE);
1128             if (!buf) 
1129                 goto stop_output;
1130             for (i = 0; i < MAX_LDRIVES; ++i) {
1131                 if (!ha->hdr[i].is_logdrv || 
1132                     (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
1133                     continue;
1134                 /* 5.a get host drive list */
1135                 TRACE2(("host_get() drv_no %d\n",i));           
1136                 phg = (gdth_hget_str *)buf;
1137                 gdtcmd.Service = CACHESERVICE;
1138                 gdtcmd.OpCode = GDT_IOCTL;
1139                 gdtcmd.u.ioctl.p_param = virt_to_bus(phg);
1140                 gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str);
1141                 gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
1142                 gdtcmd.u.ioctl.channel = i;
1143                 phg->entries = MAX_HDRIVES;
1144                 phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
1145 #if LINUX_VERSION_CODE >= 0x020322
1146                 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
1147                 if (scp->SCp.Status != S_OK) 
1148 #else
1149                 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
1150                 if (scp.SCp.Status != S_OK) 
1151 #endif
1152                 {
1153                     ha->hdr[i].ldr_no = i;
1154                     ha->hdr[i].rw_attribs = 0;
1155                     ha->hdr[i].start_sec = 0;
1156                 } else {
1157                     for (j = 0; j < phg->entries; ++j) {
1158                         k = phg->entry[j].host_drive;
1159                         if (k >= MAX_LDRIVES)
1160                             continue;
1161                         ha->hdr[k].ldr_no = phg->entry[j].log_drive;
1162                         ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
1163                         ha->hdr[k].start_sec = phg->entry[j].start_sec;
1164                     }
1165                 }
1166             }
1167             gdth_ioctl_free(hanum, buf);
1168
1169             for (i = 0; i < MAX_HDRIVES; ++i) {
1170                 if (!(ha->hdr[i].present))
1171                     continue;
1172                 
1173                 size = sprintf(buffer+len,
1174                                "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
1175                                i, ha->hdr[i].ldr_no);
1176                 len += size;  pos = begin + len;
1177                 flag = TRUE;
1178
1179                 size = sprintf(buffer+len,
1180                                " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
1181                                ha->hdr[i].size/2048, ha->hdr[i].start_sec);
1182                 len += size;  pos = begin + len;
1183                 if (pos < offset) {
1184                     len = 0;
1185                     begin = pos;
1186                 }
1187                 if (pos > offset + length)
1188                     goto stop_output;
1189             }
1190         
1191             if (!flag) {
1192                 size = sprintf(buffer+len, "\n --\n");
1193                 len += size;  pos = begin + len;
1194             }
1195         }
1196
1197         /* controller events */
1198         size = sprintf(buffer+len,"\nController Events:\n");
1199         len += size;  pos = begin + len;
1200
1201         for (id = -1;;) {
1202             id = gdth_read_event(ha, id, &estr);
1203             if (estr.event_source == 0)
1204                 break;
1205             if (estr.event_data.eu.driver.ionode == hanum &&
1206                 estr.event_source == ES_ASYNC) { 
1207                 gdth_log_event(&estr.event_data, hrec);
1208                 do_gettimeofday(&tv);
1209                 sec = (int)(tv.tv_sec - estr.first_stamp);
1210                 if (sec < 0) sec = 0;
1211                 size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
1212                                sec/3600, sec%3600/60, sec%60, hrec);
1213                 len += size;  pos = begin + len;
1214                 if (pos < offset) {
1215                     len = 0;
1216                     begin = pos;
1217                 }
1218                 if (pos > offset + length)
1219                     goto stop_output;
1220             }
1221             if (id == -1)
1222                 break;
1223         }
1224     } else {
1225         /* request from tool (GDTMON,..) */
1226         piord = (gdth_iord_str *)ha->pscratch;
1227         if (piord == NULL)
1228             goto stop_output;
1229         length = piord->size;
1230         memcpy(buffer+len, (char *)piord, length);
1231         gdth_ioctl_free(hanum, ha->pscratch);
1232         len = length; 
1233     }
1234
1235 stop_output:
1236 #if LINUX_VERSION_CODE >= 0x020322
1237     scsi_release_command(scp);
1238     scsi_free_host_dev(sdev);
1239 #endif
1240     *start = buffer +(offset-begin);
1241     len -= (offset-begin);
1242     if (len > length)
1243         len = length;
1244     TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n",
1245             len,(int)pos,(int)begin,(int)offset,length,size));
1246     return(len);
1247 }
1248
1249 static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 
1250                         char *cmnd, int timeout)
1251 {
1252     unsigned bufflen;
1253 #if LINUX_VERSION_CODE >= 0x020407
1254     DECLARE_COMPLETION(wait);
1255 #elif LINUX_VERSION_CODE >= 0x020322
1256     DECLARE_MUTEX_LOCKED(sem);
1257 #else
1258     struct semaphore sem = MUTEX_LOCKED;
1259 #endif
1260
1261     TRACE2(("gdth_do_cmd()\n"));
1262     if (gdtcmd != NULL) { 
1263         scp->SCp.this_residual = IOCTL_PRI;
1264         bufflen = sizeof(gdth_cmd_str);
1265     } else {
1266         scp->SCp.this_residual = DEFAULT_PRI;
1267         bufflen = 0;
1268     }
1269     scp->request.rq_status = RQ_SCSI_BUSY;
1270 #if LINUX_VERSION_CODE >= 0x020407
1271     scp->request.waiting = &wait;
1272     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
1273     wait_for_completion(&wait);
1274 #else
1275     scp->request.sem = &sem;
1276 #if LINUX_VERSION_CODE >= 0x020322
1277     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
1278 #else
1279     GDTH_LOCK_SCSI_DOCMD();
1280     scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
1281     GDTH_UNLOCK_SCSI_DOCMD();
1282 #endif
1283     down(&sem);
1284 #endif
1285 }
1286
1287 void gdth_scsi_done(Scsi_Cmnd *scp)
1288 {
1289     TRACE2(("gdth_scsi_done()\n"));
1290
1291     scp->request.rq_status = RQ_SCSI_DONE;
1292
1293 #if LINUX_VERSION_CODE >= 0x020407
1294     if (scp->request.waiting != NULL)
1295         complete(scp->request.waiting);
1296 #else
1297     if (scp->request.sem != NULL)
1298         up(scp->request.sem);
1299 #endif
1300 }
1301
1302 static char *gdth_ioctl_alloc(int hanum, ushort size, int scratch)
1303 {
1304     gdth_ha_str *ha;
1305     ulong flags;
1306     char *ret_val;
1307
1308     if (size == 0 || size > GDTH_SCRATCH)
1309         return FALSE;
1310
1311     ha = HADATA(gdth_ctr_tab[hanum]);
1312     GDTH_LOCK_HA(ha, flags);
1313
1314     if (scratch) { 
1315         if (!ha->scratch_busy) {
1316             ha->scratch_busy = TRUE;
1317             ret_val = ha->pscratch;
1318         } else
1319             ret_val = NULL;
1320     } else {
1321 #if LINUX_VERSION_CODE >= 0x020322
1322         ret_val = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 
1323                                             GDTH_SCRATCH_ORD);
1324 #else
1325         ret_val = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA);
1326 #endif
1327     }
1328
1329     GDTH_UNLOCK_HA(ha, flags);
1330     return ret_val;
1331 }
1332
1333 static void gdth_ioctl_free(int hanum, char *buf)
1334 {
1335     gdth_ha_str *ha;
1336     ulong flags;
1337
1338     ha = HADATA(gdth_ctr_tab[hanum]);
1339     GDTH_LOCK_HA(ha, flags);
1340
1341     if (buf == ha->pscratch) {
1342         ha->scratch_busy = FALSE;
1343     } else {
1344 #if LINUX_VERSION_CODE >= 0x020322
1345         free_pages((unsigned long)buf, GDTH_SCRATCH_ORD);
1346 #else
1347         scsi_init_free((void *)buf, GDTH_SCRATCH);
1348 #endif
1349     }
1350
1351     GDTH_UNLOCK_HA(ha, flags);
1352 }
1353
1354 static int gdth_ioctl_check_bin(int hanum, ushort size)
1355 {
1356     gdth_ha_str *ha;
1357     ulong flags;
1358     int ret_val;
1359
1360     ha = HADATA(gdth_ctr_tab[hanum]);
1361     GDTH_LOCK_HA(ha, flags);
1362
1363     ret_val = FALSE;
1364     if (ha->scratch_busy) {
1365         if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size)
1366             ret_val = TRUE;
1367     }
1368     GDTH_UNLOCK_HA(ha, flags);
1369     return ret_val;
1370 }
1371
1372
1373 static void gdth_wait_completion(int hanum, int busnum, int id)
1374 {
1375     gdth_ha_str *ha;
1376     ulong flags;
1377     int i;
1378     Scsi_Cmnd *scp;
1379     unchar b;
1380
1381     ha = HADATA(gdth_ctr_tab[hanum]);
1382     GDTH_LOCK_HA(ha, flags);
1383
1384     for (i = 0; i < GDTH_MAXCMDS; ++i) {
1385         scp = ha->cmd_tab[i].cmnd;
1386         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1387         if (!SPECIAL_SCP(scp) && scp->target == (unchar)id && 
1388             b == (unchar)busnum) {
1389             scp->SCp.have_data_in = 0;
1390             GDTH_UNLOCK_HA(ha, flags);
1391             while (!scp->SCp.have_data_in)
1392                 barrier();
1393             GDTH_LOCK_SCSI_DONE(flags);
1394             scp->scsi_done(scp);
1395             GDTH_UNLOCK_SCSI_DONE(flags);
1396         GDTH_LOCK_HA(ha, flags);
1397         }
1398     }
1399     GDTH_UNLOCK_HA(ha, flags);
1400 }
1401
1402 static void gdth_stop_timeout(int hanum, int busnum, int id)
1403 {
1404     gdth_ha_str *ha;
1405     ulong flags;
1406     Scsi_Cmnd *scp;
1407     unchar b;
1408
1409     ha = HADATA(gdth_ctr_tab[hanum]);
1410     GDTH_LOCK_HA(ha, flags);
1411
1412     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
1413         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1414         if (scp->target == (unchar)id && b == (unchar)busnum) {
1415             TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
1416             scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
1417         }
1418     }
1419     GDTH_UNLOCK_HA(ha, flags);
1420 }
1421
1422 static void gdth_start_timeout(int hanum, int busnum, int id)
1423 {
1424     gdth_ha_str *ha;
1425     ulong flags;
1426     Scsi_Cmnd *scp;
1427     unchar b;
1428
1429     ha = HADATA(gdth_ctr_tab[hanum]);
1430     GDTH_LOCK_HA(ha, flags);
1431
1432     for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
1433         b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1434         if (scp->target == (unchar)id && b == (unchar)busnum) {
1435             TRACE2(("gdth_start_timeout(): update_timeout()\n"));
1436             gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
1437         }
1438     }
1439     GDTH_UNLOCK_HA(ha, flags);
1440 }
1441
1442 static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
1443 {
1444     int oldto;
1445
1446     oldto = scp->timeout_per_command;
1447     scp->timeout_per_command = timeout;
1448
1449 #if LINUX_VERSION_CODE >= 0x02014B
1450     if (timeout == 0) {
1451         del_timer(&scp->eh_timeout);
1452         scp->eh_timeout.data = (unsigned long) NULL;
1453         scp->eh_timeout.expires = 0;
1454     } else {
1455         if (scp->eh_timeout.data != (unsigned long) NULL) 
1456             del_timer(&scp->eh_timeout);
1457         scp->eh_timeout.data = (unsigned long) scp;
1458         scp->eh_timeout.expires = jiffies + timeout;
1459         add_timer(&scp->eh_timeout);
1460     }
1461 #else
1462     if (timeout > 0) {
1463         if (timer_table[SCSI_TIMER].expires == 0) {
1464             timer_table[SCSI_TIMER].expires = jiffies + timeout;
1465             timer_active |= 1 << SCSI_TIMER;
1466         } else {
1467             if (time_before(jiffies + timeout < timer_table[SCSI_TIMER].expires))
1468                 timer_table[SCSI_TIMER].expires = jiffies + timeout;
1469         }
1470     }
1471 #endif
1472
1473     return oldto;
1474 }