File: /usr/src/linux/drivers/scsi/gdth_proc.c

1     /* gdth_proc.c 
2      * $Id: gdth_proc.c,v 1.33 2001/08/10 07:54:39 achim 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 (jiffies + timeout < timer_table[SCSI_TIMER].expires)
1468                     timer_table[SCSI_TIMER].expires = jiffies + timeout;
1469             }
1470         }
1471     #endif
1472     
1473         return oldto;
1474     }
1475