gdth_proc.c 22.4 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/* gdth_proc.c 
2
 * $Id: gdth_proc.c,v 1.43 2006/01/11 16:15:00 achim Exp $
Linus Torvalds's avatar
Linus Torvalds committed
3 4 5
 */

#include <linux/completion.h>
6
#include <linux/slab.h>
Linus Torvalds's avatar
Linus Torvalds committed
7

Al Viro's avatar
Al Viro committed
8
int gdth_set_info(struct Scsi_Host *host, char *buffer, int length)
Linus Torvalds's avatar
Linus Torvalds committed
9
{
10
    gdth_ha_str *ha = shost_priv(host);
11
    int ret_val = -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
12

13
    TRACE2(("gdth_set_info() ha %d\n",ha->hanum,));
Linus Torvalds's avatar
Linus Torvalds committed
14 15 16 17 18

    if (length >= 4) {
        if (strncmp(buffer,"gdth",4) == 0) {
            buffer += 5;
            length -= 5;
19
            ret_val = gdth_set_asc_info(host, buffer, length, ha);
Linus Torvalds's avatar
Linus Torvalds committed
20 21
        }
    }
22

Linus Torvalds's avatar
Linus Torvalds committed
23 24 25
    return ret_val;
}
         
26
static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
27
                        int length, gdth_ha_str *ha)
Linus Torvalds's avatar
Linus Torvalds committed
28
{
29 30
    int orig_length, drive, wb_mode;
    int i, found;
Linus Torvalds's avatar
Linus Torvalds committed
31 32
    gdth_cmd_str    gdtcmd;
    gdth_cpar_str   *pcpar;
33
    u64         paddr;
Linus Torvalds's avatar
Linus Torvalds committed
34 35 36 37 38

    char            cmnd[MAX_COMMAND_SIZE];
    memset(cmnd, 0xff, 12);
    memset(&gdtcmd, 0, sizeof(gdth_cmd_str));

39
    TRACE2(("gdth_set_asc_info() ha %d\n",ha->hanum));
Linus Torvalds's avatar
Linus Torvalds committed
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
    orig_length = length + 5;
    drive = -1;
    wb_mode = 0;
    found = FALSE;

    if (length >= 5 && strncmp(buffer,"flush",5)==0) {
        buffer += 6;
        length -= 6;
        if (length && *buffer>='0' && *buffer<='9') {
            drive = (int)(*buffer-'0');
            ++buffer; --length;
            if (length && *buffer>='0' && *buffer<='9') {
                drive = drive*10 + (int)(*buffer-'0');
                ++buffer; --length;
            }
            printk("GDT: Flushing host drive %d .. ",drive);
        } else {
            printk("GDT: Flushing all host drives .. ");
        }
        for (i = 0; i < MAX_HDRIVES; ++i) {
            if (ha->hdr[i].present) {
                if (drive != -1 && i != drive)
                    continue;
                found = TRUE;
                gdtcmd.Service = CACHESERVICE;
                gdtcmd.OpCode = GDT_FLUSH;
                if (ha->cache_feat & GDT_64BIT) {
                    gdtcmd.u.cache64.DeviceNo = i;
                    gdtcmd.u.cache64.BlockNo = 1;
                } else {
                    gdtcmd.u.cache.DeviceNo = i;
                    gdtcmd.u.cache.BlockNo = 1;
                }
73 74

                gdth_execute(host, &gdtcmd, cmnd, 30, NULL);
Linus Torvalds's avatar
Linus Torvalds committed
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
            }
        }
        if (!found)
            printk("\nNo host drive found !\n");
        else
            printk("Done.\n");
        return(orig_length);
    }

    if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
        buffer += 8;
        length -= 8;
        printk("GDT: Disabling write back permanently .. ");
        wb_mode = 1;
    } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
        buffer += 7;
        length -= 7;
        printk("GDT: Enabling write back permanently .. ");
        wb_mode = 2;
    } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
        buffer += 7;
        length -= 7;
        printk("GDT: Disabling write back commands .. ");
        if (ha->cache_feat & GDT_WR_THROUGH) {
            gdth_write_through = TRUE;
            printk("Done.\n");
        } else {
            printk("Not supported !\n");
        }
        return(orig_length);
    } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
        buffer += 6;
        length -= 6;
        printk("GDT: Enabling write back commands .. ");
        gdth_write_through = FALSE;
        printk("Done.\n");
        return(orig_length);
    }

    if (wb_mode) {
115
        if (!gdth_ioctl_alloc(ha, sizeof(gdth_cpar_str), TRUE, &paddr))
Linus Torvalds's avatar
Linus Torvalds committed
116 117 118 119 120 121 122 123 124 125
            return(-EBUSY);
        pcpar = (gdth_cpar_str *)ha->pscratch;
        memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
        gdtcmd.Service = CACHESERVICE;
        gdtcmd.OpCode = GDT_IOCTL;
        gdtcmd.u.ioctl.p_param = paddr;
        gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
        gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
        gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
        pcpar->write_back = wb_mode==1 ? 0:1;
126 127 128

        gdth_execute(host, &gdtcmd, cmnd, 30, NULL);

129
        gdth_ioctl_free(ha, GDTH_SCRATCH, ha->pscratch, paddr);
Linus Torvalds's avatar
Linus Torvalds committed
130 131 132 133 134 135 136 137
        printk("Done.\n");
        return(orig_length);
    }

    printk("GDT: Unknown command: %s  Length: %d\n",buffer,length);
    return(-EINVAL);
}

Al Viro's avatar
Al Viro committed
138
int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
Linus Torvalds's avatar
Linus Torvalds committed
139
{
Al Viro's avatar
Al Viro committed
140
    gdth_ha_str *ha = shost_priv(host);
141
    int hlen;
Linus Torvalds's avatar
Linus Torvalds committed
142 143
    int id, i, j, k, sec, flag;
    int no_mdrv = 0, drv_no, is_mirr;
144 145
    u32 cnt;
    u64 paddr;
Linus Torvalds's avatar
Linus Torvalds committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
    int rc = -ENOMEM;

    gdth_cmd_str *gdtcmd;
    gdth_evt_str *estr;
    char hrec[161];
    struct timeval tv;

    char *buf;
    gdth_dskstat_str *pds;
    gdth_diskinfo_str *pdi;
    gdth_arrayinf_str *pai;
    gdth_defcnt_str *pdef;
    gdth_cdrinfo_str *pcdi;
    gdth_hget_str *phg;
    char cmnd[MAX_COMMAND_SIZE];

    gdtcmd = kmalloc(sizeof(*gdtcmd), GFP_KERNEL);
    estr = kmalloc(sizeof(*estr), GFP_KERNEL);
    if (!gdtcmd || !estr)
165
        goto free_fail;
Linus Torvalds's avatar
Linus Torvalds committed
166 167 168 169

    memset(cmnd, 0xff, 12);
    memset(gdtcmd, 0, sizeof(gdth_cmd_str));

170
    TRACE2(("gdth_get_info() ha %d\n",ha->hanum));
Linus Torvalds's avatar
Linus Torvalds committed
171 172 173 174 175

    
    /* request is i.e. "cat /proc/scsi/gdth/0" */ 
    /* format: %-15s\t%-10s\t%-15s\t%s */
    /* driver parameters */
Al Viro's avatar
Al Viro committed
176
    seq_printf(m, "Driver Parameters:\n");
Linus Torvalds's avatar
Linus Torvalds committed
177 178 179
    if (reserve_list[0] == 0xff)
        strcpy(hrec, "--");
    else {
180
        hlen = sprintf(hrec, "%d", reserve_list[0]);
Linus Torvalds's avatar
Linus Torvalds committed
181 182 183
        for (i = 1;  i < MAX_RES_ARGS; i++) {
            if (reserve_list[i] == 0xff) 
                break;
184
            hlen += snprintf(hrec + hlen , 161 - hlen, ",%d", reserve_list[i]);
Linus Torvalds's avatar
Linus Torvalds committed
185 186
        }
    }
Al Viro's avatar
Al Viro committed
187
    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
188 189
                   " reserve_mode: \t%d         \treserve_list:  \t%s\n",
                   reserve_mode, hrec);
Al Viro's avatar
Al Viro committed
190
    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
191 192 193 194
                   " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
                   max_ids, hdr_channel);

    /* controller information */
Al Viro's avatar
Al Viro committed
195 196
    seq_printf(m,"\nDisk Array Controller Information:\n");
    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
197
                   " Number:       \t%d         \tName:          \t%s\n",
Al Viro's avatar
Al Viro committed
198
                   ha->hanum, ha->binfo.type_string);
Linus Torvalds's avatar
Linus Torvalds committed
199

Al Viro's avatar
Al Viro committed
200 201 202
    seq_printf(m,
                   " Driver Ver.:  \t%-10s\tFirmware Ver.: \t",
                   GDTH_VERSION_STR);
Linus Torvalds's avatar
Linus Torvalds committed
203
    if (ha->more_proc)
Al Viro's avatar
Al Viro committed
204
        seq_printf(m, "%d.%02d.%02d-%c%03X\n", 
205 206 207
                (u8)(ha->binfo.upd_fw_ver>>24),
                (u8)(ha->binfo.upd_fw_ver>>16),
                (u8)(ha->binfo.upd_fw_ver),
Linus Torvalds's avatar
Linus Torvalds committed
208 209 210
                ha->bfeat.raid ? 'R':'N',
                ha->binfo.upd_revision);
    else
Al Viro's avatar
Al Viro committed
211
        seq_printf(m, "%d.%02d\n", (u8)(ha->cpar.version>>8),
212
                (u8)(ha->cpar.version));
Linus Torvalds's avatar
Linus Torvalds committed
213
 
Al Viro's avatar
Al Viro committed
214
    if (ha->more_proc)
Linus Torvalds's avatar
Linus Torvalds committed
215
        /* more information: 1. about controller */
Al Viro's avatar
Al Viro committed
216
        seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
217 218 219 220 221
                       " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
                       ha->binfo.ser_no, ha->binfo.memsize / 1024);

#ifdef GDTH_DMA_STATISTICS
    /* controller statistics */
Al Viro's avatar
Al Viro committed
222 223
    seq_printf(m,"\nController Statistics:\n");
    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
224 225 226 227 228 229
                   " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n",
                   ha->dma32_cnt, ha->dma64_cnt);
#endif

    if (ha->more_proc) {
        /* more information: 2. about physical devices */
Al Viro's avatar
Al Viro committed
230
        seq_printf(m, "\nPhysical Devices:");
Linus Torvalds's avatar
Linus Torvalds committed
231 232
        flag = FALSE;
            
233
        buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
Linus Torvalds's avatar
Linus Torvalds committed
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
        if (!buf) 
            goto stop_output;
        for (i = 0; i < ha->bus_cnt; ++i) {
            /* 2.a statistics (and retries/reassigns) */
            TRACE2(("pdr_statistics() chn %d\n",i));                
            pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
            gdtcmd->Service = CACHESERVICE;
            gdtcmd->OpCode = GDT_IOCTL;
            gdtcmd->u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
            gdtcmd->u.ioctl.param_size = 3*GDTH_SCRATCH/4;
            gdtcmd->u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
            gdtcmd->u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
            pds->bid = ha->raw[i].local_no;
            pds->first = 0;
            pds->entries = ha->raw[i].pdev_cnt;
249
            cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(u32)) /
Linus Torvalds's avatar
Linus Torvalds committed
250 251 252
                sizeof(pds->list[0]);
            if (pds->entries > cnt)
                pds->entries = cnt;
253 254

            if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) != S_OK)
Linus Torvalds's avatar
Linus Torvalds committed
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
                pds->count = 0;

            /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
            for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
                /* 2.b drive info */
                TRACE2(("scsi_drv_info() chn %d dev %d\n",
                    i, ha->raw[i].id_list[j]));             
                pdi = (gdth_diskinfo_str *)buf;
                gdtcmd->Service = CACHESERVICE;
                gdtcmd->OpCode = GDT_IOCTL;
                gdtcmd->u.ioctl.p_param = paddr;
                gdtcmd->u.ioctl.param_size = sizeof(gdth_diskinfo_str);
                gdtcmd->u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
                gdtcmd->u.ioctl.channel = 
                    ha->raw[i].address | ha->raw[i].id_list[j];
270 271

                if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
Linus Torvalds's avatar
Linus Torvalds committed
272 273 274 275
                    strncpy(hrec,pdi->vendor,8);
                    strncpy(hrec+8,pdi->product,16);
                    strncpy(hrec+24,pdi->revision,4);
                    hrec[28] = 0;
Al Viro's avatar
Al Viro committed
276
                    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
277 278 279 280 281 282 283 284
                                   "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
                                   'A'+i,pdi->target_id,pdi->lun,hrec);
                    flag = TRUE;
                    pdi->no_ldrive &= 0xffff;
                    if (pdi->no_ldrive == 0xffff)
                        strcpy(hrec,"--");
                    else
                        sprintf(hrec,"%d",pdi->no_ldrive);
Al Viro's avatar
Al Viro committed
285
                    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
286 287 288 289 290 291 292 293 294 295 296 297
                                   " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
                                   pdi->blkcnt/(1024*1024/pdi->blksize),
                                   hrec);
                } else {
                    pdi->devtype = 0xff;
                }
                    
                if (pdi->devtype == 0) {
                    /* search retries/reassigns */
                    for (k = 0; k < pds->count; ++k) {
                        if (pds->list[k].tid == pdi->target_id &&
                            pds->list[k].lun == pdi->lun) {
Al Viro's avatar
Al Viro committed
298
                            seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
                                           " Retries:      \t%-6d    \tReassigns:     \t%d\n",
                                           pds->list[k].retries,
                                           pds->list[k].reassigns);
                            break;
                        }
                    }
                    /* 2.c grown defects */
                    TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
                            i, ha->raw[i].id_list[j]));             
                    pdef = (gdth_defcnt_str *)buf;
                    gdtcmd->Service = CACHESERVICE;
                    gdtcmd->OpCode = GDT_IOCTL;
                    gdtcmd->u.ioctl.p_param = paddr;
                    gdtcmd->u.ioctl.param_size = sizeof(gdth_defcnt_str);
                    gdtcmd->u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
                    gdtcmd->u.ioctl.channel = 
                        ha->raw[i].address | ha->raw[i].id_list[j];
                    pdef->sddc_type = 0x08;
317 318

                    if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
Al Viro's avatar
Al Viro committed
319
                        seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
320 321 322 323 324 325
                                       " Grown Defects:\t%d\n",
                                       pdef->sddc_cnt);
                    }
                }
            }
        }
326
        gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
Linus Torvalds's avatar
Linus Torvalds committed
327

Al Viro's avatar
Al Viro committed
328 329
        if (!flag)
            seq_printf(m, "\n --\n");
Linus Torvalds's avatar
Linus Torvalds committed
330 331

        /* 3. about logical drives */
Al Viro's avatar
Al Viro committed
332
        seq_printf(m,"\nLogical Drives:");
Linus Torvalds's avatar
Linus Torvalds committed
333 334
        flag = FALSE;

335
        buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
Linus Torvalds's avatar
Linus Torvalds committed
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
        if (!buf) 
            goto stop_output;
        for (i = 0; i < MAX_LDRIVES; ++i) {
            if (!ha->hdr[i].is_logdrv)
                continue;
            drv_no = i;
            j = k = 0;
            is_mirr = FALSE;
            do {
                /* 3.a log. drive info */
                TRACE2(("cache_drv_info() drive no %d\n",drv_no));
                pcdi = (gdth_cdrinfo_str *)buf;
                gdtcmd->Service = CACHESERVICE;
                gdtcmd->OpCode = GDT_IOCTL;
                gdtcmd->u.ioctl.p_param = paddr;
                gdtcmd->u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
                gdtcmd->u.ioctl.subfunc = CACHE_DRV_INFO;
                gdtcmd->u.ioctl.channel = drv_no;
354
                if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) != S_OK)
Linus Torvalds's avatar
Linus Torvalds committed
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
                    break;
                pcdi->ld_dtype >>= 16;
                j++;
                if (pcdi->ld_dtype > 2) {
                    strcpy(hrec, "missing");
                } else if (pcdi->ld_error & 1) {
                    strcpy(hrec, "fault");
                } else if (pcdi->ld_error & 2) {
                    strcpy(hrec, "invalid");
                    k++; j--;
                } else {
                    strcpy(hrec, "ok");
                }
                    
                if (drv_no == i) {
Al Viro's avatar
Al Viro committed
370
                    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
                                   "\n Number:       \t%-2d        \tStatus:        \t%s\n",
                                   drv_no, hrec);
                    flag = TRUE;
                    no_mdrv = pcdi->cd_ldcnt;
                    if (no_mdrv > 1 || pcdi->ld_slave != -1) {
                        is_mirr = TRUE;
                        strcpy(hrec, "RAID-1");
                    } else if (pcdi->ld_dtype == 0) {
                        strcpy(hrec, "Disk");
                    } else if (pcdi->ld_dtype == 1) {
                        strcpy(hrec, "RAID-0");
                    } else if (pcdi->ld_dtype == 2) {
                        strcpy(hrec, "Chain");
                    } else {
                        strcpy(hrec, "???");
                    }
Al Viro's avatar
Al Viro committed
387
                    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
388 389 390 391
                                   " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
                                   pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
                                   hrec);
                } else {
Al Viro's avatar
Al Viro committed
392
                    seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
393 394 395 396 397 398
                                   " Slave Number: \t%-2d        \tStatus:        \t%s\n",
                                   drv_no & 0x7fff, hrec);
                }
                drv_no = pcdi->ld_slave;
            } while (drv_no != -1);
             
Al Viro's avatar
Al Viro committed
399 400
            if (is_mirr)
                seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
401 402
                               " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
                               no_mdrv - j - k, k);
Al Viro's avatar
Al Viro committed
403

Linus Torvalds's avatar
Linus Torvalds committed
404 405 406 407
            if (!ha->hdr[i].is_arraydrv)
                strcpy(hrec, "--");
            else
                sprintf(hrec, "%d", ha->hdr[i].master_no);
Al Viro's avatar
Al Viro committed
408
            seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
409 410
                           " To Array Drv.:\t%s\n", hrec);
        }       
411
        gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
Linus Torvalds's avatar
Linus Torvalds committed
412
        
Al Viro's avatar
Al Viro committed
413 414
        if (!flag)
            seq_printf(m, "\n --\n");
Linus Torvalds's avatar
Linus Torvalds committed
415 416

        /* 4. about array drives */
Al Viro's avatar
Al Viro committed
417
        seq_printf(m,"\nArray Drives:");
Linus Torvalds's avatar
Linus Torvalds committed
418 419
        flag = FALSE;

420
        buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
Linus Torvalds's avatar
Linus Torvalds committed
421 422 423 424 425 426 427 428 429 430 431 432 433 434
        if (!buf) 
            goto stop_output;
        for (i = 0; i < MAX_LDRIVES; ++i) {
            if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
                continue;
            /* 4.a array drive info */
            TRACE2(("array_info() drive no %d\n",i));
            pai = (gdth_arrayinf_str *)buf;
            gdtcmd->Service = CACHESERVICE;
            gdtcmd->OpCode = GDT_IOCTL;
            gdtcmd->u.ioctl.p_param = paddr;
            gdtcmd->u.ioctl.param_size = sizeof(gdth_arrayinf_str);
            gdtcmd->u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
            gdtcmd->u.ioctl.channel = i;
435
            if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
Linus Torvalds's avatar
Linus Torvalds committed
436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
                if (pai->ai_state == 0)
                    strcpy(hrec, "idle");
                else if (pai->ai_state == 2)
                    strcpy(hrec, "build");
                else if (pai->ai_state == 4)
                    strcpy(hrec, "ready");
                else if (pai->ai_state == 6)
                    strcpy(hrec, "fail");
                else if (pai->ai_state == 8 || pai->ai_state == 10)
                    strcpy(hrec, "rebuild");
                else
                    strcpy(hrec, "error");
                if (pai->ai_ext_state & 0x10)
                    strcat(hrec, "/expand");
                else if (pai->ai_ext_state & 0x1)
                    strcat(hrec, "/patch");
Al Viro's avatar
Al Viro committed
452
                seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
453 454 455 456 457 458 459 460 461 462 463 464
                               "\n Number:       \t%-2d        \tStatus:        \t%s\n",
                               i,hrec);
                flag = TRUE;

                if (pai->ai_type == 0)
                    strcpy(hrec, "RAID-0");
                else if (pai->ai_type == 4)
                    strcpy(hrec, "RAID-4");
                else if (pai->ai_type == 5)
                    strcpy(hrec, "RAID-5");
                else 
                    strcpy(hrec, "RAID-10");
Al Viro's avatar
Al Viro committed
465
                seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
466 467 468 469 470
                               " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
                               pai->ai_size/(1024*1024/pai->ai_secsize),
                               hrec);
            }
        }
471
        gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
Linus Torvalds's avatar
Linus Torvalds committed
472
        
Al Viro's avatar
Al Viro committed
473 474
        if (!flag)
            seq_printf(m, "\n --\n");
Linus Torvalds's avatar
Linus Torvalds committed
475 476

        /* 5. about host drives */
Al Viro's avatar
Al Viro committed
477
        seq_printf(m,"\nHost Drives:");
Linus Torvalds's avatar
Linus Torvalds committed
478 479
        flag = FALSE;

480
        buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr);
Linus Torvalds's avatar
Linus Torvalds committed
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
        if (!buf) 
            goto stop_output;
        for (i = 0; i < MAX_LDRIVES; ++i) {
            if (!ha->hdr[i].is_logdrv || 
                (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
                continue;
            /* 5.a get host drive list */
            TRACE2(("host_get() drv_no %d\n",i));           
            phg = (gdth_hget_str *)buf;
            gdtcmd->Service = CACHESERVICE;
            gdtcmd->OpCode = GDT_IOCTL;
            gdtcmd->u.ioctl.p_param = paddr;
            gdtcmd->u.ioctl.param_size = sizeof(gdth_hget_str);
            gdtcmd->u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
            gdtcmd->u.ioctl.channel = i;
            phg->entries = MAX_HDRIVES;
            phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
498
            if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
Linus Torvalds's avatar
Linus Torvalds committed
499 500 501 502 503 504 505 506 507 508 509 510 511 512
                ha->hdr[i].ldr_no = i;
                ha->hdr[i].rw_attribs = 0;
                ha->hdr[i].start_sec = 0;
            } else {
                for (j = 0; j < phg->entries; ++j) {
                    k = phg->entry[j].host_drive;
                    if (k >= MAX_LDRIVES)
                        continue;
                    ha->hdr[k].ldr_no = phg->entry[j].log_drive;
                    ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
                    ha->hdr[k].start_sec = phg->entry[j].start_sec;
                }
            }
        }
513
        gdth_ioctl_free(ha, sizeof(gdth_hget_str), buf, paddr);
Linus Torvalds's avatar
Linus Torvalds committed
514 515 516 517 518

        for (i = 0; i < MAX_HDRIVES; ++i) {
            if (!(ha->hdr[i].present))
                continue;
              
Al Viro's avatar
Al Viro committed
519
            seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
520 521 522 523
                           "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
                           i, ha->hdr[i].ldr_no);
            flag = TRUE;

Al Viro's avatar
Al Viro committed
524
            seq_printf(m,
Linus Torvalds's avatar
Linus Torvalds committed
525
                           " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
526
                           (u32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
Linus Torvalds's avatar
Linus Torvalds committed
527 528
        }
        
Al Viro's avatar
Al Viro committed
529 530
        if (!flag)
            seq_printf(m, "\n --\n");
Linus Torvalds's avatar
Linus Torvalds committed
531 532 533
    }

    /* controller events */
Al Viro's avatar
Al Viro committed
534
    seq_printf(m,"\nController Events:\n");
Linus Torvalds's avatar
Linus Torvalds committed
535 536 537 538 539

    for (id = -1;;) {
        id = gdth_read_event(ha, id, estr);
        if (estr->event_source == 0)
            break;
540
        if (estr->event_data.eu.driver.ionode == ha->hanum &&
Linus Torvalds's avatar
Linus Torvalds committed
541 542 543 544 545
            estr->event_source == ES_ASYNC) { 
            gdth_log_event(&estr->event_data, hrec);
            do_gettimeofday(&tv);
            sec = (int)(tv.tv_sec - estr->first_stamp);
            if (sec < 0) sec = 0;
Al Viro's avatar
Al Viro committed
546
            seq_printf(m," date- %02d:%02d:%02d\t%s\n",
Linus Torvalds's avatar
Linus Torvalds committed
547 548 549 550 551 552
                           sec/3600, sec%3600/60, sec%60, hrec);
        }
        if (id == -1)
            break;
    }
stop_output:
Al Viro's avatar
Al Viro committed
553
    rc = 0;
Linus Torvalds's avatar
Linus Torvalds committed
554 555 556 557 558 559
free_fail:
    kfree(gdtcmd);
    kfree(estr);
    return rc;
}

560
static char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch,
561
                              u64 *paddr)
Linus Torvalds's avatar
Linus Torvalds committed
562
{
563
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
    char *ret_val;

    if (size == 0)
        return NULL;

    spin_lock_irqsave(&ha->smp_lock, flags);

    if (!ha->scratch_busy && size <= GDTH_SCRATCH) {
        ha->scratch_busy = TRUE;
        ret_val = ha->pscratch;
        *paddr = ha->scratch_phys;
    } else if (scratch) {
        ret_val = NULL;
    } else {
        dma_addr_t dma_addr;

        ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr);
        *paddr = dma_addr;
    }

    spin_unlock_irqrestore(&ha->smp_lock, flags);
    return ret_val;
}

588
static void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr)
Linus Torvalds's avatar
Linus Torvalds committed
589
{
590
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
591 592

    if (buf == ha->pscratch) {
593
	spin_lock_irqsave(&ha->smp_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
594
        ha->scratch_busy = FALSE;
595
	spin_unlock_irqrestore(&ha->smp_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
596 597 598 599 600 601
    } else {
        pci_free_consistent(ha->pdev, size, buf, paddr);
    }
}

#ifdef GDTH_IOCTL_PROC
602
static int gdth_ioctl_check_bin(gdth_ha_str *ha, u16 size)
Linus Torvalds's avatar
Linus Torvalds committed
603
{
604
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
605 606 607 608 609 610
    int ret_val;

    spin_lock_irqsave(&ha->smp_lock, flags);

    ret_val = FALSE;
    if (ha->scratch_busy) {
611
        if (((gdth_iord_str *)ha->pscratch)->size == (u32)size)
Linus Torvalds's avatar
Linus Torvalds committed
612 613 614 615 616 617 618
            ret_val = TRUE;
    }
    spin_unlock_irqrestore(&ha->smp_lock, flags);
    return ret_val;
}
#endif

619
static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
Linus Torvalds's avatar
Linus Torvalds committed
620
{
621
    unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
622 623
    int i;
    Scsi_Cmnd *scp;
624
    struct gdth_cmndinfo *cmndinfo;
625
    u8 b, t;
Linus Torvalds's avatar
Linus Torvalds committed
626 627 628 629 630

    spin_lock_irqsave(&ha->smp_lock, flags);

    for (i = 0; i < GDTH_MAXCMDS; ++i) {
        scp = ha->cmd_tab[i].cmnd;
631
        cmndinfo = gdth_cmnd_priv(scp);
Linus Torvalds's avatar
Linus Torvalds committed
632

633
        b = scp->device->channel;
Linus Torvalds's avatar
Linus Torvalds committed
634
        t = scp->device->id;
635 636
        if (!SPECIAL_SCP(scp) && t == (u8)id && 
            b == (u8)busnum) {
637
            cmndinfo->wait_for_completion = 0;
Linus Torvalds's avatar
Linus Torvalds committed
638
            spin_unlock_irqrestore(&ha->smp_lock, flags);
639
            while (!cmndinfo->wait_for_completion)
Linus Torvalds's avatar
Linus Torvalds committed
640 641 642 643 644 645
                barrier();
            spin_lock_irqsave(&ha->smp_lock, flags);
        }
    }
    spin_unlock_irqrestore(&ha->smp_lock, flags);
}