patch-2.2.6 linux/drivers/scsi/gdth_proc.c

Next file: linux/drivers/scsi/gdth_proc.h
Previous file: linux/drivers/scsi/gdth.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.5/linux/drivers/scsi/gdth_proc.c linux/drivers/scsi/gdth_proc.c
@@ -1,5 +1,5 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.11 1998/12/17 15:52:35 achim Exp $
+ * $Id: gdth_proc.c,v 1.13 1999/03/22 16:12:53 achim Exp $
  */
 
 #include "gdth_ioctl.h"
@@ -68,7 +68,6 @@
 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
 {
     int             orig_length, drive, wb_mode;
-    char            cmnd[12];
     int             i, found;
     gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
@@ -76,7 +75,6 @@
 
     TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
-    memset(cmnd, 0,10);
     orig_length = length + 5;
     drive = -1;
     wb_mode = 0;
@@ -107,18 +105,7 @@
                 gdtcmd.u.cache.DeviceNo = i;
                 gdtcmd.u.cache.BlockNo = 1;
                 gdtcmd.u.cache.sg_canz = 0;
-                {
-                    struct semaphore sem = MUTEX_LOCKED;
-                    scp.request.rq_status = RQ_SCSI_BUSY;
-                    scp.request.sem = &sem;
-                    scp.SCp.this_residual = IOCTL_PRI;
-                    GDTH_LOCK_SCSI_DOCMD();
-                    scsi_do_cmd(&scp, cmnd, &gdtcmd,
-                                sizeof(gdth_cmd_str), gdth_scsi_done,
-                                30*HZ, 1);
-                    GDTH_UNLOCK_SCSI_DOCMD();
-                    down(&sem);
-                }
+                gdth_do_cmd(&scp, &gdtcmd, 30);
             }
         }
         if (!found)
@@ -159,13 +146,9 @@
     }
 
     if (wb_mode) {
-        pcpar = (gdth_cpar_str *)kmalloc( sizeof(gdth_cpar_str),
-            GFP_ATOMIC | GFP_DMA );
-        if (pcpar == NULL) {
-            TRACE2(("gdth_set_info(): Unable to allocate memory.\n"));
-            printk("Unable to allocate memory.\n");
-            return(-EINVAL);
-        }
+        if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str)))
+            return(-EBUSY);
+        pcpar = (gdth_cpar_str *)ha->pscratch;
         memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
@@ -175,18 +158,8 @@
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
         pcpar->write_back = wb_mode==1 ? 0:1;
-        {
-            struct semaphore sem = MUTEX_LOCKED;
-            scp.request.rq_status = RQ_SCSI_BUSY;
-            scp.request.sem = &sem;
-            scp.SCp.this_residual = IOCTL_PRI;
-            GDTH_LOCK_SCSI_DOCMD();
-            scsi_do_cmd(&scp, cmnd, &gdtcmd, sizeof(gdth_cmd_str),
-                        gdth_scsi_done, 30*HZ, 1);
-            GDTH_UNLOCK_SCSI_DOCMD();
-            down(&sem);
-        }
-        kfree( pcpar );
+        gdth_do_cmd(&scp, &gdtcmd, 30);
+        gdth_ioctl_free(hanum);
         printk("Done.\n");
         return(orig_length);
     }
@@ -197,21 +170,23 @@
 
 static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
 {
-    char            cmnd[12];
     unchar          i, j;
     gdth_ha_str     *ha;
     gdth_iowr_str   *piowr;
     gdth_iord_str   *piord;
     gdth_cmd_str    *pcmd;
+    gdth_evt_str    *pevt;
     ulong32         *ppadd, add_size;
+    ulong32         *ppadd2, add_size2;
     ulong           flags;
 
     TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
-    memset(cmnd, 0,10);
     piowr = (gdth_iowr_str *)buffer;
     piord = NULL;
     pcmd = NULL;
+    ppadd = ppadd2 = NULL;
+    add_size = add_size2 = 0;
 
     if (length < GDTOFFSOF(gdth_iowr_str,iu))
         return(-EINVAL);
@@ -238,6 +213,7 @@
             }
         } else if (piowr->service == SCSIRAWSERVICE) {
             add_size = pcmd->u.raw.sdlen;
+            add_size2 = pcmd->u.raw.sense_len;
             if (ha->raw_feat & SCATTER_GATHER) {
                 ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr;
                 pcmd->u.raw.sdata = 0xffffffff;
@@ -247,32 +223,26 @@
                 ppadd = &pcmd->u.raw.sdata;
                 pcmd->u.raw.sg_ranz = 0;
             }
+            ppadd2 = &pcmd->u.raw.sense_data;
         } else {
             return(-EINVAL);
         }
-        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) + add_size ))
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str)+add_size+add_size2 ))
             return(-EBUSY);
         piord = (gdth_iord_str *)ha->pscratch;
 
-        piord->size = sizeof(gdth_iord_str) + add_size;
+        piord->size = sizeof(gdth_iord_str) + add_size + add_size2;
         if (add_size > 0) {
             memcpy(piord->iu.general.data, piowr->iu.general.data, add_size);
             *ppadd = virt_to_bus(piord->iu.general.data);
         }
-        /* do IOCTL */
-        {
-            struct semaphore sem = MUTEX_LOCKED;
-            scp.request.rq_status = RQ_SCSI_BUSY;
-            scp.request.sem = &sem;
-            scp.SCp.this_residual = IOCTL_PRI;
-            GDTH_LOCK_SCSI_DOCMD();
-            scsi_do_cmd(&scp, cmnd, pcmd,
-                        sizeof(gdth_cmd_str), gdth_scsi_done,
-                        piowr->timeout*HZ, 1);
-            GDTH_UNLOCK_SCSI_DOCMD();
-            down(&sem);
-            piord->status = (ulong32)scp.SCp.Message;
+        if (add_size2 > 0) {
+            memcpy(piord->iu.general.data+add_size, piowr->iu.general.data, add_size2);
+            *ppadd2 = virt_to_bus(piord->iu.general.data+add_size);
         }
+        /* do IOCTL */
+        gdth_do_cmd(&scp, pcmd, piowr->timeout);
+        piord->status = (ulong32)scp.SCp.Message;
         break;
 
       case GDTIOCTL_DRVERS:
@@ -381,12 +351,21 @@
             return(-EBUSY);
         piord = (gdth_iord_str *)ha->pscratch;
         if (piowr->iu.event.erase == 0xff) {
-            gdth_store_event(ha, 
-                             ((gdth_evt_str *)piowr->iu.event.evt)->event_source,
-                             ((gdth_evt_str *)piowr->iu.event.evt)->event_idx,
-                             &((gdth_evt_str *)piowr->iu.event.evt)->event_data);
-            if (((gdth_evt_str *)piowr->iu.event.evt)->event_source == ES_ASYNC)
-                gdth_log_event(&((gdth_evt_str *)piowr->iu.event.evt)->event_data);
+            pevt = (gdth_evt_str *)piowr->iu.event.evt;
+            if (pevt->event_source == ES_TEST) 
+                pevt->event_data.size = sizeof(pevt->event_data.eu.test);
+            else if (pevt->event_source == ES_DRIVER) 
+                pevt->event_data.size = sizeof(pevt->event_data.eu.driver);
+            else if (pevt->event_source == ES_SYNC) 
+                pevt->event_data.size = sizeof(pevt->event_data.eu.sync);
+            else {
+                pevt->event_data.size = sizeof(pevt->event_data.eu.async);
+                gdth_log_event(&pevt->event_data, NULL);
+            }
+	    GDTH_LOCK_HA(ha, flags);
+            gdth_store_event(ha, pevt->event_source, pevt->event_idx,
+                             &pevt->event_data);
+	    GDTH_UNLOCK_HA(ha, flags);
         } else if (piowr->iu.event.erase == 0xfe) {
             gdth_clear_events();
         } else if (piowr->iu.event.erase == 0) {
@@ -416,28 +395,98 @@
     off_t begin = 0,pos = 0;
     gdth_ha_str *ha;
     gdth_iord_str *piord;
-    int id;
+    int id, i, j, k, sec, flag;
+    int no_mdrv = 0, drv_no, is_mirr;
+    ulong32 cnt;
+
+    gdth_cmd_str gdtcmd;
+    gdth_evt_str estr;
+    Scsi_Cmnd scp;
+    Scsi_Device sdev;
+    char hrec[161];
+    struct timeval tv;
+
+    gdth_dskstat_str *pds;
+    gdth_diskinfo_str *pdi;
+    gdth_arrayinf_str *pai;
+    gdth_defcnt_str *pdef;
+    gdth_cdrinfo_str *pcdi;
+    gdth_hget_str *phg;
 
     TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
     ha = HADATA(gdth_ctr_tab[hanum]);
     id = length;
 
+    memset(&sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    sdev.host = gdth_ctr_vtab[vh];
+    sdev.id = sdev.host->this_id;
+    scp.cmd_len = 12;
+    scp.host = gdth_ctr_vtab[vh];
+    scp.target = sdev.host->this_id;
+    scp.device = &sdev;
+    scp.use_sg = 0;
+
     /* look for buffer ID in length */
     if (id > 1) {
-#if LINUX_VERSION_CODE >= 0x020000
+        /* request is i.e. "cat /proc/scsi/gdth/0" */ 
+        /* format: %-15s\t%-10s\t%-15s\t%s */
+        /* driver parameters */
+        size = sprintf(buffer+len,"Driver Parameters:\n");
+        len += size;  pos = begin + len;
+        if (reserve_list[0] == 0xff)
+            strcpy(hrec, "--");
+        else {
+            sprintf(hrec, "%d", reserve_list[0]);
+            for (i = 1;  i < MAX_RES_ARGS; i++) {
+                if (reserve_list[i] == 0xff) 
+                    break;
+                sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
+            }
+        }
         size = sprintf(buffer+len,
-                       "%s Disk Array Controller\n",
-                       ha->ctr_name);
-#else
+                       " reserve_mode: \t%d         \treserve_list:  \t%s\n",
+                       reserve_mode, hrec);
+        len += size;  pos = begin + len;
         size = sprintf(buffer+len,
-                       "%s Disk Array Controller (Bus %d)\n",
-                       ha->ctr_name,busnum);
+                       " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
+                       max_ids, hdr_channel);
+        len += size;  pos = begin + len;
+
+        if (pos < offset) {
+            len = 0;
+            begin = pos;
+        }
+        if (pos > offset + length)
+            goto stop_output;
+
+        /* controller information */
+        size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
+        len += size;  pos = begin + len;
+#if LINUX_VERSION_CODE >= 0x020000
+        strcpy(hrec, ha->binfo.type_string);
+#else
+        sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
 #endif
+        size = sprintf(buffer+len,
+                       " Number:       \t%d         \tName:          \t%s\n",
+                       hanum, hrec);
         len += size;  pos = begin + len;
+
+        if (ha->more_proc)
+            sprintf(hrec, "%d.%02d.%02d-%c%03X", 
+                    (unchar)(ha->binfo.upd_fw_ver>>24),
+                    (unchar)(ha->binfo.upd_fw_ver>>16),
+                    (unchar)(ha->binfo.upd_fw_ver),
+                    ha->bfeat.raid ? 'R':'N',
+                    ha->binfo.upd_revision);
+        else
+            sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
+                    (unchar)(ha->cpar.version));
+
         size = sprintf(buffer+len,
-                       "Firmware Version: %d.%2d\tDriver Version: %s\n",
-                       (unchar)(ha->cpar.version>>8),
-                       (unchar)(ha->cpar.version),GDTH_VERSION_STR);
+                       " Driver Ver.:  \t%-10s\tFirmware Ver.: \t%s\n",
+                       GDTH_VERSION_STR, hrec);
         len += size;  pos = begin + len;
  
         if (pos < offset) {
@@ -447,7 +496,412 @@
         if (pos > offset + length)
             goto stop_output;
 
+        if (ha->more_proc) {
+            /* more information: 1. about controller */
+            size = sprintf(buffer+len,
+                           " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
+                           ha->binfo.ser_no, ha->binfo.memsize / 1024);
+            len += size;  pos = begin + len;
+
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+
+            /* 2. about physical devices */
+            size = sprintf(buffer+len,"\nPhysical Devices:");
+            len += size;  pos = begin + len;
+	    flag = FALSE;
+            
+            if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
+                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 *)(ha->pscratch + GDTH_SCRATCH/4);
+                gdtcmd.BoardNode = LOCALBOARD;
+                gdtcmd.Service = CACHESERVICE;
+                gdtcmd.OpCode = GDT_IOCTL;
+                gdtcmd.u.ioctl.p_param = virt_to_bus(pds);
+                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;
+                cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
+                    sizeof(pds->list[0]);
+                if (pds->entries > cnt)
+                    pds->entries = cnt;
+                gdth_do_cmd(&scp, &gdtcmd, 30);
+                if (scp.SCp.Message != S_OK) 
+                    pds->count = 0;
+                TRACE2(("pdr_statistics() entries %d status %d\n",
+                        pds->count, scp.SCp.Message));
+
+                /* 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 *)ha->pscratch;
+                    gdtcmd.BoardNode = LOCALBOARD;
+                    gdtcmd.Service = CACHESERVICE;
+                    gdtcmd.OpCode = GDT_IOCTL;
+                    gdtcmd.u.ioctl.p_param = virt_to_bus(pdi);
+                    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];
+                    gdth_do_cmd(&scp, &gdtcmd, 30);
+                    if (scp.SCp.Message == S_OK) {
+                        strncpy(hrec,pdi->vendor,8);
+                        strncpy(hrec+8,pdi->product,16);
+                        strncpy(hrec+24,pdi->revision,4);
+                        hrec[28] = 0;
+                        size = sprintf(buffer+len,
+                                       "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
+                                       'A'+i,pdi->target_id,pdi->lun,hrec);
+                        len += size;  pos = begin + len;
+			flag = TRUE;
+                        pdi->no_ldrive &= 0xffff;
+                        if (pdi->no_ldrive == 0xffff)
+                            strcpy(hrec,"--");
+                        else
+                            sprintf(hrec,"%d",pdi->no_ldrive);
+                        size = sprintf(buffer+len,
+                                       " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
+                                       pdi->blkcnt/(1024*1024/pdi->blksize),
+                                       hrec);
+                        len += size;  pos = begin + len;
+                    } 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) {
+                                size = sprintf(buffer+len,
+                                               " Retries:      \t%-6d    \tReassigns:     \t%d\n",
+                                               pds->list[k].retries,
+                                               pds->list[k].reassigns);
+                                len += size;  pos = begin + len;
+                                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 *)ha->pscratch;
+                        gdtcmd.BoardNode = LOCALBOARD;
+                        gdtcmd.Service = CACHESERVICE;
+                        gdtcmd.OpCode = GDT_IOCTL;
+                        gdtcmd.u.ioctl.p_param = virt_to_bus(pdef);
+                        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;
+                        gdth_do_cmd(&scp, &gdtcmd, 30);
+                        if (scp.SCp.Message == S_OK) {
+                            size = sprintf(buffer+len,
+                                           " Grown Defects:\t%d\n",
+                                           pdef->sddc_cnt);
+                            len += size;  pos = begin + len;
+                        }
+                    }
+                }
+            }
+            gdth_ioctl_free(hanum);
+
+	    if (!flag) {
+		size = sprintf(buffer+len, "\n --\n");
+		len += size;  pos = begin + len;
+	    }
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+
+            /* 3. about logical drives */
+            size = sprintf(buffer+len,"\nLogical Drives:");
+            len += size;  pos = begin + len;
+	    flag = FALSE;
+
+            if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
+                goto stop_output;
+            for (i = 0; i < MAX_HDRIVES; ++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 *)ha->pscratch;
+                    gdtcmd.BoardNode = LOCALBOARD;
+                    gdtcmd.Service = CACHESERVICE;
+                    gdtcmd.OpCode = GDT_IOCTL;
+                    gdtcmd.u.ioctl.p_param = virt_to_bus(pcdi);
+                    gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
+                    gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
+                    gdtcmd.u.ioctl.channel = drv_no;
+                    gdth_do_cmd(&scp, &gdtcmd, 30);
+                    if (scp.SCp.Message != S_OK)
+                        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) {
+                        size = sprintf(buffer+len,
+                                       "\n Number:       \t%-2d        \tStatus:        \t%s\n",
+                                       drv_no, hrec);
+                        len += size;  pos = begin + len;
+			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, "???");
+                        }
+                        size = sprintf(buffer+len,
+                                       " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
+                                       pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
+                                       hrec);
+                        len += size;  pos = begin + len;
+                    } else {
+                        size = sprintf(buffer+len,
+                                       " Slave Number: \t%-2d        \tStatus:        \t%s\n",
+                                       drv_no & 0x7fff, hrec);
+                        len += size;  pos = begin + len;
+                    }
+                    drv_no = pcdi->ld_slave;
+                } while (drv_no != -1);
+                
+                if (is_mirr) {
+                    size = sprintf(buffer+len,
+                                   " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
+                                   no_mdrv - j - k, k);
+                    len += size;  pos = begin + len;
+                }
+                
+                if (!ha->hdr[i].is_arraydrv)
+                    strcpy(hrec, "--");
+                else
+                    sprintf(hrec, "%d", ha->hdr[i].master_no);
+                size = sprintf(buffer+len,
+                               " To Array Drv.:\t%s\n", hrec);
+                len += size;  pos = begin + len;
+            }       
+            gdth_ioctl_free(hanum);
+        
+	    if (!flag) {
+		size = sprintf(buffer+len, "\n --\n");
+		len += size;  pos = begin + len;
+	    }	
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+
+            /* 4. about array drives */
+            size = sprintf(buffer+len,"\nArray Drives:");
+            len += size;  pos = begin + len;
+	    flag = FALSE;
+
+            if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
+                goto stop_output;
+            for (i = 0; i < MAX_HDRIVES; ++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 *)ha->pscratch;
+                gdtcmd.BoardNode = LOCALBOARD;
+                gdtcmd.Service = CACHESERVICE;
+                gdtcmd.OpCode = GDT_IOCTL;
+                gdtcmd.u.ioctl.p_param = virt_to_bus(pai);
+                gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
+                gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
+                gdtcmd.u.ioctl.channel = i;
+                gdth_do_cmd(&scp, &gdtcmd, 30);
+                if (scp.SCp.Message == S_OK) {
+                    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");
+                    size = sprintf(buffer+len,
+                                   "\n Number:       \t%-2d        \tStatus:        \t%s\n",
+                                   i,hrec);
+                    len += size;  pos = begin + len;
+                    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");
+                    size = sprintf(buffer+len,
+                                   " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
+                                   pai->ai_size/(1024*1024/pai->ai_secsize),
+                                   hrec);
+                    len += size;  pos = begin + len;
+                }
+            }
+            gdth_ioctl_free(hanum);
+        
+	    if (!flag) {
+		size = sprintf(buffer+len, "\n --\n");
+		len += size;  pos = begin + len;
+	    }
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+
+            /* 5. about host drives */
+            size = sprintf(buffer+len,"\nHost Drives:");
+            len += size;  pos = begin + len;
+	    flag = FALSE;
+
+            if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
+                goto stop_output;
+            for (i = 0; i < MAX_HDRIVES; ++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 *)ha->pscratch;
+                gdtcmd.BoardNode = LOCALBOARD;
+                gdtcmd.Service = CACHESERVICE;
+                gdtcmd.OpCode = GDT_IOCTL;
+                gdtcmd.u.ioctl.p_param = virt_to_bus(phg);
+                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]); 
+                gdth_do_cmd(&scp, &gdtcmd, 30);
+                if (scp.SCp.Message != S_OK) {
+                    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_HDRIVES)
+                            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;
+                    }
+                }
+                TRACE2(("host_get entries %d status %d\n",
+                        phg->entries, scp.SCp.Message));
+            }
+            gdth_ioctl_free(hanum);
+
+            for (i = 0; i < MAX_HDRIVES; ++i) {
+                if (!(ha->hdr[i].present))
+                    continue;
+                
+                size = sprintf(buffer+len,
+                               "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
+                               i, ha->hdr[i].ldr_no);
+                len += size;  pos = begin + len;
+		flag = TRUE;
+
+                size = sprintf(buffer+len,
+                               " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
+                               ha->hdr[i].size/2048, ha->hdr[i].start_sec);
+                len += size;  pos = begin + len;
+            }
+        
+	    if (!flag) {
+		size = sprintf(buffer+len, "\n --\n");
+		len += size;  pos = begin + len;
+	    }
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+        }
+
+        /* controller events */
+        size = sprintf(buffer+len,"\nController Events:\n");
+        len += size;  pos = begin + len;
+
+        for (id = -1;;) {
+            id = gdth_read_event(ha, id, &estr);
+            if (estr.event_source == 0)
+                break;
+            if (estr.event_data.eu.driver.ionode == hanum &&
+                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;
+                size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
+                               sec/3600, sec%3600/60, sec%60, hrec);
+                len += size;  pos = begin + len;
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
+            }
+            if (id == -1)
+                break;
+        }
     } else {
+        /* request from tool (GDTMON,..) */
         piord = (gdth_iord_str *)ha->pscratch;
         if (piord == NULL)
             goto stop_output;
@@ -474,6 +928,22 @@
     return(len);
 }
 
+static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout)
+{
+    char cmnd[12];
+    struct semaphore sem = MUTEX_LOCKED;
+
+    TRACE2(("gdth_do_cmd()\n"));
+    memset(cmnd, 0, 12);
+    scp->request.rq_status = RQ_SCSI_BUSY;
+    scp->request.sem = &sem;
+    scp->SCp.this_residual = IOCTL_PRI;
+    GDTH_LOCK_SCSI_DOCMD();
+    scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), 
+                gdth_scsi_done, timeout*HZ, 1);
+    GDTH_UNLOCK_SCSI_DOCMD();
+    down(&sem);
+}
 
 void gdth_scsi_done(Scsi_Cmnd *scp)
 {
@@ -492,7 +962,7 @@
     int ret_val;
 
     if (size == 0 || size > GDTH_SCRATCH)
-        return -1;
+        return FALSE;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     GDTH_LOCK_HA(ha, flags);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)