1/* gdth_proc.c
2 * $Id: gdth_proc.c,v 1.1.1.1 2008/10/15 03:26:52 james26_jang Exp $
3 */
4
5#include "gdth_ioctl.h"
6#if LINUX_VERSION_CODE >= 0x020407
7#include <linux/completion.h>
8#endif
9
10int 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
34static 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
91static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
92#else
93static 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
207static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
208#else
209static 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
675static 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
1235stop_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
1249static 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
1287void 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
1302static 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
1333static 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
1354static 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
1373static 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
1402static 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
1422static 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
1442static 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}
1475