xref: /OK3568_Linux_fs/kernel/drivers/scsi/gdth_proc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /* gdth_proc.c
3*4882a593Smuzhiyun  * $Id: gdth_proc.c,v 1.43 2006/01/11 16:15:00 achim Exp $
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/completion.h>
7*4882a593Smuzhiyun #include <linux/slab.h>
8*4882a593Smuzhiyun 
gdth_set_info(struct Scsi_Host * host,char * buffer,int length)9*4882a593Smuzhiyun int gdth_set_info(struct Scsi_Host *host, char *buffer, int length)
10*4882a593Smuzhiyun {
11*4882a593Smuzhiyun     gdth_ha_str *ha = shost_priv(host);
12*4882a593Smuzhiyun     int ret_val = -EINVAL;
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun     TRACE2(("gdth_set_info() ha %d\n",ha->hanum,));
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun     if (length >= 4) {
17*4882a593Smuzhiyun         if (strncmp(buffer,"gdth",4) == 0) {
18*4882a593Smuzhiyun             buffer += 5;
19*4882a593Smuzhiyun             length -= 5;
20*4882a593Smuzhiyun             ret_val = gdth_set_asc_info(host, buffer, length, ha);
21*4882a593Smuzhiyun         }
22*4882a593Smuzhiyun     }
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun     return ret_val;
25*4882a593Smuzhiyun }
26*4882a593Smuzhiyun 
gdth_set_asc_info(struct Scsi_Host * host,char * buffer,int length,gdth_ha_str * ha)27*4882a593Smuzhiyun static int gdth_set_asc_info(struct Scsi_Host *host, char *buffer,
28*4882a593Smuzhiyun                         int length, gdth_ha_str *ha)
29*4882a593Smuzhiyun {
30*4882a593Smuzhiyun     int orig_length, drive, wb_mode;
31*4882a593Smuzhiyun     int i, found;
32*4882a593Smuzhiyun     gdth_cmd_str    gdtcmd;
33*4882a593Smuzhiyun     gdth_cpar_str   *pcpar;
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun     char            cmnd[MAX_COMMAND_SIZE];
36*4882a593Smuzhiyun     memset(cmnd, 0xff, 12);
37*4882a593Smuzhiyun     memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun     TRACE2(("gdth_set_asc_info() ha %d\n",ha->hanum));
40*4882a593Smuzhiyun     orig_length = length + 5;
41*4882a593Smuzhiyun     drive = -1;
42*4882a593Smuzhiyun     wb_mode = 0;
43*4882a593Smuzhiyun     found = FALSE;
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun     if (length >= 5 && strncmp(buffer,"flush",5)==0) {
46*4882a593Smuzhiyun         buffer += 6;
47*4882a593Smuzhiyun         length -= 6;
48*4882a593Smuzhiyun         if (length && *buffer>='0' && *buffer<='9') {
49*4882a593Smuzhiyun             drive = (int)(*buffer-'0');
50*4882a593Smuzhiyun             ++buffer; --length;
51*4882a593Smuzhiyun             if (length && *buffer>='0' && *buffer<='9') {
52*4882a593Smuzhiyun                 drive = drive*10 + (int)(*buffer-'0');
53*4882a593Smuzhiyun                 ++buffer; --length;
54*4882a593Smuzhiyun             }
55*4882a593Smuzhiyun             printk("GDT: Flushing host drive %d .. ",drive);
56*4882a593Smuzhiyun         } else {
57*4882a593Smuzhiyun             printk("GDT: Flushing all host drives .. ");
58*4882a593Smuzhiyun         }
59*4882a593Smuzhiyun         for (i = 0; i < MAX_HDRIVES; ++i) {
60*4882a593Smuzhiyun             if (ha->hdr[i].present) {
61*4882a593Smuzhiyun                 if (drive != -1 && i != drive)
62*4882a593Smuzhiyun                     continue;
63*4882a593Smuzhiyun                 found = TRUE;
64*4882a593Smuzhiyun                 gdtcmd.Service = CACHESERVICE;
65*4882a593Smuzhiyun                 gdtcmd.OpCode = GDT_FLUSH;
66*4882a593Smuzhiyun                 if (ha->cache_feat & GDT_64BIT) {
67*4882a593Smuzhiyun                     gdtcmd.u.cache64.DeviceNo = i;
68*4882a593Smuzhiyun                     gdtcmd.u.cache64.BlockNo = 1;
69*4882a593Smuzhiyun                 } else {
70*4882a593Smuzhiyun                     gdtcmd.u.cache.DeviceNo = i;
71*4882a593Smuzhiyun                     gdtcmd.u.cache.BlockNo = 1;
72*4882a593Smuzhiyun                 }
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun                 gdth_execute(host, &gdtcmd, cmnd, 30, NULL);
75*4882a593Smuzhiyun             }
76*4882a593Smuzhiyun         }
77*4882a593Smuzhiyun         if (!found)
78*4882a593Smuzhiyun             printk("\nNo host drive found !\n");
79*4882a593Smuzhiyun         else
80*4882a593Smuzhiyun             printk("Done.\n");
81*4882a593Smuzhiyun         return(orig_length);
82*4882a593Smuzhiyun     }
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun     if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
85*4882a593Smuzhiyun         buffer += 8;
86*4882a593Smuzhiyun         length -= 8;
87*4882a593Smuzhiyun         printk("GDT: Disabling write back permanently .. ");
88*4882a593Smuzhiyun         wb_mode = 1;
89*4882a593Smuzhiyun     } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
90*4882a593Smuzhiyun         buffer += 7;
91*4882a593Smuzhiyun         length -= 7;
92*4882a593Smuzhiyun         printk("GDT: Enabling write back permanently .. ");
93*4882a593Smuzhiyun         wb_mode = 2;
94*4882a593Smuzhiyun     } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
95*4882a593Smuzhiyun         buffer += 7;
96*4882a593Smuzhiyun         length -= 7;
97*4882a593Smuzhiyun         printk("GDT: Disabling write back commands .. ");
98*4882a593Smuzhiyun         if (ha->cache_feat & GDT_WR_THROUGH) {
99*4882a593Smuzhiyun             gdth_write_through = TRUE;
100*4882a593Smuzhiyun             printk("Done.\n");
101*4882a593Smuzhiyun         } else {
102*4882a593Smuzhiyun             printk("Not supported !\n");
103*4882a593Smuzhiyun         }
104*4882a593Smuzhiyun         return(orig_length);
105*4882a593Smuzhiyun     } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
106*4882a593Smuzhiyun         buffer += 6;
107*4882a593Smuzhiyun         length -= 6;
108*4882a593Smuzhiyun         printk("GDT: Enabling write back commands .. ");
109*4882a593Smuzhiyun         gdth_write_through = FALSE;
110*4882a593Smuzhiyun         printk("Done.\n");
111*4882a593Smuzhiyun         return(orig_length);
112*4882a593Smuzhiyun     }
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun     if (wb_mode) {
115*4882a593Smuzhiyun 	unsigned long flags;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	BUILD_BUG_ON(sizeof(gdth_cpar_str) > GDTH_SCRATCH);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->smp_lock, flags);
120*4882a593Smuzhiyun 	if (ha->scratch_busy) {
121*4882a593Smuzhiyun 	    spin_unlock_irqrestore(&ha->smp_lock, flags);
122*4882a593Smuzhiyun             return -EBUSY;
123*4882a593Smuzhiyun 	}
124*4882a593Smuzhiyun 	ha->scratch_busy = TRUE;
125*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->smp_lock, flags);
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun         pcpar = (gdth_cpar_str *)ha->pscratch;
128*4882a593Smuzhiyun         memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
129*4882a593Smuzhiyun         gdtcmd.Service = CACHESERVICE;
130*4882a593Smuzhiyun         gdtcmd.OpCode = GDT_IOCTL;
131*4882a593Smuzhiyun         gdtcmd.u.ioctl.p_param = ha->scratch_phys;
132*4882a593Smuzhiyun         gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
133*4882a593Smuzhiyun         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
134*4882a593Smuzhiyun         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
135*4882a593Smuzhiyun         pcpar->write_back = wb_mode==1 ? 0:1;
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun         gdth_execute(host, &gdtcmd, cmnd, 30, NULL);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	spin_lock_irqsave(&ha->smp_lock, flags);
140*4882a593Smuzhiyun 	ha->scratch_busy = FALSE;
141*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ha->smp_lock, flags);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun         printk("Done.\n");
144*4882a593Smuzhiyun         return(orig_length);
145*4882a593Smuzhiyun     }
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun     printk("GDT: Unknown command: %s  Length: %d\n",buffer,length);
148*4882a593Smuzhiyun     return(-EINVAL);
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
gdth_show_info(struct seq_file * m,struct Scsi_Host * host)151*4882a593Smuzhiyun int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
152*4882a593Smuzhiyun {
153*4882a593Smuzhiyun     gdth_ha_str *ha = shost_priv(host);
154*4882a593Smuzhiyun     int hlen;
155*4882a593Smuzhiyun     int id, i, j, k, sec, flag;
156*4882a593Smuzhiyun     int no_mdrv = 0, drv_no, is_mirr;
157*4882a593Smuzhiyun     u32 cnt;
158*4882a593Smuzhiyun     dma_addr_t paddr;
159*4882a593Smuzhiyun     int rc = -ENOMEM;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun     gdth_cmd_str *gdtcmd;
162*4882a593Smuzhiyun     gdth_evt_str *estr;
163*4882a593Smuzhiyun     char hrec[277];
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun     char *buf;
166*4882a593Smuzhiyun     gdth_dskstat_str *pds;
167*4882a593Smuzhiyun     gdth_diskinfo_str *pdi;
168*4882a593Smuzhiyun     gdth_arrayinf_str *pai;
169*4882a593Smuzhiyun     gdth_defcnt_str *pdef;
170*4882a593Smuzhiyun     gdth_cdrinfo_str *pcdi;
171*4882a593Smuzhiyun     gdth_hget_str *phg;
172*4882a593Smuzhiyun     char cmnd[MAX_COMMAND_SIZE];
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun     gdtcmd = kmalloc(sizeof(*gdtcmd), GFP_KERNEL);
175*4882a593Smuzhiyun     estr = kmalloc(sizeof(*estr), GFP_KERNEL);
176*4882a593Smuzhiyun     if (!gdtcmd || !estr)
177*4882a593Smuzhiyun         goto free_fail;
178*4882a593Smuzhiyun 
179*4882a593Smuzhiyun     memset(cmnd, 0xff, 12);
180*4882a593Smuzhiyun     memset(gdtcmd, 0, sizeof(gdth_cmd_str));
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun     TRACE2(("gdth_get_info() ha %d\n",ha->hanum));
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun     /* request is i.e. "cat /proc/scsi/gdth/0" */
186*4882a593Smuzhiyun     /* format: %-15s\t%-10s\t%-15s\t%s */
187*4882a593Smuzhiyun     /* driver parameters */
188*4882a593Smuzhiyun     seq_puts(m, "Driver Parameters:\n");
189*4882a593Smuzhiyun     if (reserve_list[0] == 0xff)
190*4882a593Smuzhiyun         strcpy(hrec, "--");
191*4882a593Smuzhiyun     else {
192*4882a593Smuzhiyun         hlen = sprintf(hrec, "%d", reserve_list[0]);
193*4882a593Smuzhiyun         for (i = 1;  i < MAX_RES_ARGS; i++) {
194*4882a593Smuzhiyun             if (reserve_list[i] == 0xff)
195*4882a593Smuzhiyun                 break;
196*4882a593Smuzhiyun 	    hlen += scnprintf(hrec + hlen, 161 - hlen, ",%d", reserve_list[i]);
197*4882a593Smuzhiyun         }
198*4882a593Smuzhiyun     }
199*4882a593Smuzhiyun     seq_printf(m,
200*4882a593Smuzhiyun                    " reserve_mode: \t%d         \treserve_list:  \t%s\n",
201*4882a593Smuzhiyun                    reserve_mode, hrec);
202*4882a593Smuzhiyun     seq_printf(m,
203*4882a593Smuzhiyun                    " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
204*4882a593Smuzhiyun                    max_ids, hdr_channel);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun     /* controller information */
207*4882a593Smuzhiyun     seq_puts(m, "\nDisk Array Controller Information:\n");
208*4882a593Smuzhiyun     seq_printf(m,
209*4882a593Smuzhiyun                    " Number:       \t%d         \tName:          \t%s\n",
210*4882a593Smuzhiyun                    ha->hanum, ha->binfo.type_string);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun     seq_printf(m,
213*4882a593Smuzhiyun                    " Driver Ver.:  \t%-10s\tFirmware Ver.: \t",
214*4882a593Smuzhiyun                    GDTH_VERSION_STR);
215*4882a593Smuzhiyun     if (ha->more_proc)
216*4882a593Smuzhiyun         seq_printf(m, "%d.%02d.%02d-%c%03X\n",
217*4882a593Smuzhiyun                 (u8)(ha->binfo.upd_fw_ver>>24),
218*4882a593Smuzhiyun                 (u8)(ha->binfo.upd_fw_ver>>16),
219*4882a593Smuzhiyun                 (u8)(ha->binfo.upd_fw_ver),
220*4882a593Smuzhiyun                 ha->bfeat.raid ? 'R':'N',
221*4882a593Smuzhiyun                 ha->binfo.upd_revision);
222*4882a593Smuzhiyun     else
223*4882a593Smuzhiyun         seq_printf(m, "%d.%02d\n", (u8)(ha->cpar.version>>8),
224*4882a593Smuzhiyun                 (u8)(ha->cpar.version));
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun     if (ha->more_proc)
227*4882a593Smuzhiyun         /* more information: 1. about controller */
228*4882a593Smuzhiyun         seq_printf(m,
229*4882a593Smuzhiyun                        " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
230*4882a593Smuzhiyun                        ha->binfo.ser_no, ha->binfo.memsize / 1024);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun     if (ha->more_proc) {
233*4882a593Smuzhiyun         size_t size = max_t(size_t, GDTH_SCRATCH, sizeof(gdth_hget_str));
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun         /* more information: 2. about physical devices */
236*4882a593Smuzhiyun         seq_puts(m, "\nPhysical Devices:");
237*4882a593Smuzhiyun         flag = FALSE;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun         buf = dma_alloc_coherent(&ha->pdev->dev, size, &paddr, GFP_KERNEL);
240*4882a593Smuzhiyun         if (!buf)
241*4882a593Smuzhiyun             goto stop_output;
242*4882a593Smuzhiyun         for (i = 0; i < ha->bus_cnt; ++i) {
243*4882a593Smuzhiyun             /* 2.a statistics (and retries/reassigns) */
244*4882a593Smuzhiyun             TRACE2(("pdr_statistics() chn %d\n",i));
245*4882a593Smuzhiyun             pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
246*4882a593Smuzhiyun             gdtcmd->Service = CACHESERVICE;
247*4882a593Smuzhiyun             gdtcmd->OpCode = GDT_IOCTL;
248*4882a593Smuzhiyun             gdtcmd->u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
249*4882a593Smuzhiyun             gdtcmd->u.ioctl.param_size = 3*GDTH_SCRATCH/4;
250*4882a593Smuzhiyun             gdtcmd->u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
251*4882a593Smuzhiyun             gdtcmd->u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
252*4882a593Smuzhiyun             pds->bid = ha->raw[i].local_no;
253*4882a593Smuzhiyun             pds->first = 0;
254*4882a593Smuzhiyun             pds->entries = ha->raw[i].pdev_cnt;
255*4882a593Smuzhiyun             cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(u32)) /
256*4882a593Smuzhiyun                 sizeof(pds->list[0]);
257*4882a593Smuzhiyun             if (pds->entries > cnt)
258*4882a593Smuzhiyun                 pds->entries = cnt;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun             if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) != S_OK)
261*4882a593Smuzhiyun                 pds->count = 0;
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun             /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
264*4882a593Smuzhiyun             for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
265*4882a593Smuzhiyun                 /* 2.b drive info */
266*4882a593Smuzhiyun                 TRACE2(("scsi_drv_info() chn %d dev %d\n",
267*4882a593Smuzhiyun                     i, ha->raw[i].id_list[j]));
268*4882a593Smuzhiyun                 pdi = (gdth_diskinfo_str *)buf;
269*4882a593Smuzhiyun                 gdtcmd->Service = CACHESERVICE;
270*4882a593Smuzhiyun                 gdtcmd->OpCode = GDT_IOCTL;
271*4882a593Smuzhiyun                 gdtcmd->u.ioctl.p_param = paddr;
272*4882a593Smuzhiyun                 gdtcmd->u.ioctl.param_size = sizeof(gdth_diskinfo_str);
273*4882a593Smuzhiyun                 gdtcmd->u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
274*4882a593Smuzhiyun                 gdtcmd->u.ioctl.channel =
275*4882a593Smuzhiyun                     ha->raw[i].address | ha->raw[i].id_list[j];
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun                 if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
278*4882a593Smuzhiyun                     strncpy(hrec,pdi->vendor,8);
279*4882a593Smuzhiyun                     strncpy(hrec+8,pdi->product,16);
280*4882a593Smuzhiyun                     strncpy(hrec+24,pdi->revision,4);
281*4882a593Smuzhiyun                     hrec[28] = 0;
282*4882a593Smuzhiyun                     seq_printf(m,
283*4882a593Smuzhiyun                                    "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
284*4882a593Smuzhiyun                                    'A'+i,pdi->target_id,pdi->lun,hrec);
285*4882a593Smuzhiyun                     flag = TRUE;
286*4882a593Smuzhiyun                     pdi->no_ldrive &= 0xffff;
287*4882a593Smuzhiyun                     if (pdi->no_ldrive == 0xffff)
288*4882a593Smuzhiyun                         strcpy(hrec,"--");
289*4882a593Smuzhiyun                     else
290*4882a593Smuzhiyun                         sprintf(hrec,"%d",pdi->no_ldrive);
291*4882a593Smuzhiyun                     seq_printf(m,
292*4882a593Smuzhiyun                                    " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
293*4882a593Smuzhiyun                                    pdi->blkcnt/(1024*1024/pdi->blksize),
294*4882a593Smuzhiyun                                    hrec);
295*4882a593Smuzhiyun                 } else {
296*4882a593Smuzhiyun                     pdi->devtype = 0xff;
297*4882a593Smuzhiyun                 }
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun                 if (pdi->devtype == 0) {
300*4882a593Smuzhiyun                     /* search retries/reassigns */
301*4882a593Smuzhiyun                     for (k = 0; k < pds->count; ++k) {
302*4882a593Smuzhiyun                         if (pds->list[k].tid == pdi->target_id &&
303*4882a593Smuzhiyun                             pds->list[k].lun == pdi->lun) {
304*4882a593Smuzhiyun                             seq_printf(m,
305*4882a593Smuzhiyun                                            " Retries:      \t%-6d    \tReassigns:     \t%d\n",
306*4882a593Smuzhiyun                                            pds->list[k].retries,
307*4882a593Smuzhiyun                                            pds->list[k].reassigns);
308*4882a593Smuzhiyun                             break;
309*4882a593Smuzhiyun                         }
310*4882a593Smuzhiyun                     }
311*4882a593Smuzhiyun                     /* 2.c grown defects */
312*4882a593Smuzhiyun                     TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
313*4882a593Smuzhiyun                             i, ha->raw[i].id_list[j]));
314*4882a593Smuzhiyun                     pdef = (gdth_defcnt_str *)buf;
315*4882a593Smuzhiyun                     gdtcmd->Service = CACHESERVICE;
316*4882a593Smuzhiyun                     gdtcmd->OpCode = GDT_IOCTL;
317*4882a593Smuzhiyun                     gdtcmd->u.ioctl.p_param = paddr;
318*4882a593Smuzhiyun                     gdtcmd->u.ioctl.param_size = sizeof(gdth_defcnt_str);
319*4882a593Smuzhiyun                     gdtcmd->u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
320*4882a593Smuzhiyun                     gdtcmd->u.ioctl.channel =
321*4882a593Smuzhiyun                         ha->raw[i].address | ha->raw[i].id_list[j];
322*4882a593Smuzhiyun                     pdef->sddc_type = 0x08;
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun                     if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
325*4882a593Smuzhiyun                         seq_printf(m,
326*4882a593Smuzhiyun                                        " Grown Defects:\t%d\n",
327*4882a593Smuzhiyun                                        pdef->sddc_cnt);
328*4882a593Smuzhiyun                     }
329*4882a593Smuzhiyun                 }
330*4882a593Smuzhiyun             }
331*4882a593Smuzhiyun         }
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun         if (!flag)
334*4882a593Smuzhiyun             seq_puts(m, "\n --\n");
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun         /* 3. about logical drives */
337*4882a593Smuzhiyun         seq_puts(m, "\nLogical Drives:");
338*4882a593Smuzhiyun         flag = FALSE;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun         for (i = 0; i < MAX_LDRIVES; ++i) {
341*4882a593Smuzhiyun             if (!ha->hdr[i].is_logdrv)
342*4882a593Smuzhiyun                 continue;
343*4882a593Smuzhiyun             drv_no = i;
344*4882a593Smuzhiyun             j = k = 0;
345*4882a593Smuzhiyun             is_mirr = FALSE;
346*4882a593Smuzhiyun             do {
347*4882a593Smuzhiyun                 /* 3.a log. drive info */
348*4882a593Smuzhiyun                 TRACE2(("cache_drv_info() drive no %d\n",drv_no));
349*4882a593Smuzhiyun                 pcdi = (gdth_cdrinfo_str *)buf;
350*4882a593Smuzhiyun                 gdtcmd->Service = CACHESERVICE;
351*4882a593Smuzhiyun                 gdtcmd->OpCode = GDT_IOCTL;
352*4882a593Smuzhiyun                 gdtcmd->u.ioctl.p_param = paddr;
353*4882a593Smuzhiyun                 gdtcmd->u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
354*4882a593Smuzhiyun                 gdtcmd->u.ioctl.subfunc = CACHE_DRV_INFO;
355*4882a593Smuzhiyun                 gdtcmd->u.ioctl.channel = drv_no;
356*4882a593Smuzhiyun                 if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) != S_OK)
357*4882a593Smuzhiyun                     break;
358*4882a593Smuzhiyun                 pcdi->ld_dtype >>= 16;
359*4882a593Smuzhiyun                 j++;
360*4882a593Smuzhiyun                 if (pcdi->ld_dtype > 2) {
361*4882a593Smuzhiyun                     strcpy(hrec, "missing");
362*4882a593Smuzhiyun                 } else if (pcdi->ld_error & 1) {
363*4882a593Smuzhiyun                     strcpy(hrec, "fault");
364*4882a593Smuzhiyun                 } else if (pcdi->ld_error & 2) {
365*4882a593Smuzhiyun                     strcpy(hrec, "invalid");
366*4882a593Smuzhiyun                     k++; j--;
367*4882a593Smuzhiyun                 } else {
368*4882a593Smuzhiyun                     strcpy(hrec, "ok");
369*4882a593Smuzhiyun                 }
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun                 if (drv_no == i) {
372*4882a593Smuzhiyun                     seq_printf(m,
373*4882a593Smuzhiyun                                    "\n Number:       \t%-2d        \tStatus:        \t%s\n",
374*4882a593Smuzhiyun                                    drv_no, hrec);
375*4882a593Smuzhiyun                     flag = TRUE;
376*4882a593Smuzhiyun                     no_mdrv = pcdi->cd_ldcnt;
377*4882a593Smuzhiyun                     if (no_mdrv > 1 || pcdi->ld_slave != -1) {
378*4882a593Smuzhiyun                         is_mirr = TRUE;
379*4882a593Smuzhiyun                         strcpy(hrec, "RAID-1");
380*4882a593Smuzhiyun                     } else if (pcdi->ld_dtype == 0) {
381*4882a593Smuzhiyun                         strcpy(hrec, "Disk");
382*4882a593Smuzhiyun                     } else if (pcdi->ld_dtype == 1) {
383*4882a593Smuzhiyun                         strcpy(hrec, "RAID-0");
384*4882a593Smuzhiyun                     } else if (pcdi->ld_dtype == 2) {
385*4882a593Smuzhiyun                         strcpy(hrec, "Chain");
386*4882a593Smuzhiyun                     } else {
387*4882a593Smuzhiyun                         strcpy(hrec, "???");
388*4882a593Smuzhiyun                     }
389*4882a593Smuzhiyun                     seq_printf(m,
390*4882a593Smuzhiyun                                    " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
391*4882a593Smuzhiyun                                    pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
392*4882a593Smuzhiyun                                    hrec);
393*4882a593Smuzhiyun                 } else {
394*4882a593Smuzhiyun                     seq_printf(m,
395*4882a593Smuzhiyun                                    " Slave Number: \t%-2d        \tStatus:        \t%s\n",
396*4882a593Smuzhiyun                                    drv_no & 0x7fff, hrec);
397*4882a593Smuzhiyun                 }
398*4882a593Smuzhiyun                 drv_no = pcdi->ld_slave;
399*4882a593Smuzhiyun             } while (drv_no != -1);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun             if (is_mirr)
402*4882a593Smuzhiyun                 seq_printf(m,
403*4882a593Smuzhiyun                                " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
404*4882a593Smuzhiyun                                no_mdrv - j - k, k);
405*4882a593Smuzhiyun 
406*4882a593Smuzhiyun             if (!ha->hdr[i].is_arraydrv)
407*4882a593Smuzhiyun                 strcpy(hrec, "--");
408*4882a593Smuzhiyun             else
409*4882a593Smuzhiyun                 sprintf(hrec, "%d", ha->hdr[i].master_no);
410*4882a593Smuzhiyun             seq_printf(m,
411*4882a593Smuzhiyun                            " To Array Drv.:\t%s\n", hrec);
412*4882a593Smuzhiyun         }
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun         if (!flag)
415*4882a593Smuzhiyun             seq_puts(m, "\n --\n");
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun         /* 4. about array drives */
418*4882a593Smuzhiyun         seq_puts(m, "\nArray Drives:");
419*4882a593Smuzhiyun         flag = FALSE;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun         for (i = 0; i < MAX_LDRIVES; ++i) {
422*4882a593Smuzhiyun             if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
423*4882a593Smuzhiyun                 continue;
424*4882a593Smuzhiyun             /* 4.a array drive info */
425*4882a593Smuzhiyun             TRACE2(("array_info() drive no %d\n",i));
426*4882a593Smuzhiyun             pai = (gdth_arrayinf_str *)buf;
427*4882a593Smuzhiyun             gdtcmd->Service = CACHESERVICE;
428*4882a593Smuzhiyun             gdtcmd->OpCode = GDT_IOCTL;
429*4882a593Smuzhiyun             gdtcmd->u.ioctl.p_param = paddr;
430*4882a593Smuzhiyun             gdtcmd->u.ioctl.param_size = sizeof(gdth_arrayinf_str);
431*4882a593Smuzhiyun             gdtcmd->u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
432*4882a593Smuzhiyun             gdtcmd->u.ioctl.channel = i;
433*4882a593Smuzhiyun             if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
434*4882a593Smuzhiyun                 if (pai->ai_state == 0)
435*4882a593Smuzhiyun                     strcpy(hrec, "idle");
436*4882a593Smuzhiyun                 else if (pai->ai_state == 2)
437*4882a593Smuzhiyun                     strcpy(hrec, "build");
438*4882a593Smuzhiyun                 else if (pai->ai_state == 4)
439*4882a593Smuzhiyun                     strcpy(hrec, "ready");
440*4882a593Smuzhiyun                 else if (pai->ai_state == 6)
441*4882a593Smuzhiyun                     strcpy(hrec, "fail");
442*4882a593Smuzhiyun                 else if (pai->ai_state == 8 || pai->ai_state == 10)
443*4882a593Smuzhiyun                     strcpy(hrec, "rebuild");
444*4882a593Smuzhiyun                 else
445*4882a593Smuzhiyun                     strcpy(hrec, "error");
446*4882a593Smuzhiyun                 if (pai->ai_ext_state & 0x10)
447*4882a593Smuzhiyun                     strcat(hrec, "/expand");
448*4882a593Smuzhiyun                 else if (pai->ai_ext_state & 0x1)
449*4882a593Smuzhiyun                     strcat(hrec, "/patch");
450*4882a593Smuzhiyun                 seq_printf(m,
451*4882a593Smuzhiyun                                "\n Number:       \t%-2d        \tStatus:        \t%s\n",
452*4882a593Smuzhiyun                                i,hrec);
453*4882a593Smuzhiyun                 flag = TRUE;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun                 if (pai->ai_type == 0)
456*4882a593Smuzhiyun                     strcpy(hrec, "RAID-0");
457*4882a593Smuzhiyun                 else if (pai->ai_type == 4)
458*4882a593Smuzhiyun                     strcpy(hrec, "RAID-4");
459*4882a593Smuzhiyun                 else if (pai->ai_type == 5)
460*4882a593Smuzhiyun                     strcpy(hrec, "RAID-5");
461*4882a593Smuzhiyun                 else
462*4882a593Smuzhiyun                     strcpy(hrec, "RAID-10");
463*4882a593Smuzhiyun                 seq_printf(m,
464*4882a593Smuzhiyun                                " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
465*4882a593Smuzhiyun                                pai->ai_size/(1024*1024/pai->ai_secsize),
466*4882a593Smuzhiyun                                hrec);
467*4882a593Smuzhiyun             }
468*4882a593Smuzhiyun         }
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun         if (!flag)
471*4882a593Smuzhiyun             seq_puts(m, "\n --\n");
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun         /* 5. about host drives */
474*4882a593Smuzhiyun         seq_puts(m, "\nHost Drives:");
475*4882a593Smuzhiyun         flag = FALSE;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun         for (i = 0; i < MAX_LDRIVES; ++i) {
478*4882a593Smuzhiyun             if (!ha->hdr[i].is_logdrv ||
479*4882a593Smuzhiyun                 (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
480*4882a593Smuzhiyun                 continue;
481*4882a593Smuzhiyun             /* 5.a get host drive list */
482*4882a593Smuzhiyun             TRACE2(("host_get() drv_no %d\n",i));
483*4882a593Smuzhiyun             phg = (gdth_hget_str *)buf;
484*4882a593Smuzhiyun             gdtcmd->Service = CACHESERVICE;
485*4882a593Smuzhiyun             gdtcmd->OpCode = GDT_IOCTL;
486*4882a593Smuzhiyun             gdtcmd->u.ioctl.p_param = paddr;
487*4882a593Smuzhiyun             gdtcmd->u.ioctl.param_size = sizeof(gdth_hget_str);
488*4882a593Smuzhiyun             gdtcmd->u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
489*4882a593Smuzhiyun             gdtcmd->u.ioctl.channel = i;
490*4882a593Smuzhiyun             phg->entries = MAX_HDRIVES;
491*4882a593Smuzhiyun             phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]);
492*4882a593Smuzhiyun             if (gdth_execute(host, gdtcmd, cmnd, 30, NULL) == S_OK) {
493*4882a593Smuzhiyun                 ha->hdr[i].ldr_no = i;
494*4882a593Smuzhiyun                 ha->hdr[i].rw_attribs = 0;
495*4882a593Smuzhiyun                 ha->hdr[i].start_sec = 0;
496*4882a593Smuzhiyun             } else {
497*4882a593Smuzhiyun                 for (j = 0; j < phg->entries; ++j) {
498*4882a593Smuzhiyun                     k = phg->entry[j].host_drive;
499*4882a593Smuzhiyun                     if (k >= MAX_LDRIVES)
500*4882a593Smuzhiyun                         continue;
501*4882a593Smuzhiyun                     ha->hdr[k].ldr_no = phg->entry[j].log_drive;
502*4882a593Smuzhiyun                     ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
503*4882a593Smuzhiyun                     ha->hdr[k].start_sec = phg->entry[j].start_sec;
504*4882a593Smuzhiyun                 }
505*4882a593Smuzhiyun             }
506*4882a593Smuzhiyun         }
507*4882a593Smuzhiyun 	dma_free_coherent(&ha->pdev->dev, size, buf, paddr);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun         for (i = 0; i < MAX_HDRIVES; ++i) {
510*4882a593Smuzhiyun             if (!(ha->hdr[i].present))
511*4882a593Smuzhiyun                 continue;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun             seq_printf(m,
514*4882a593Smuzhiyun                            "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
515*4882a593Smuzhiyun                            i, ha->hdr[i].ldr_no);
516*4882a593Smuzhiyun             flag = TRUE;
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun             seq_printf(m,
519*4882a593Smuzhiyun                            " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
520*4882a593Smuzhiyun                            (u32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
521*4882a593Smuzhiyun         }
522*4882a593Smuzhiyun 
523*4882a593Smuzhiyun         if (!flag)
524*4882a593Smuzhiyun             seq_puts(m, "\n --\n");
525*4882a593Smuzhiyun     }
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun     /* controller events */
528*4882a593Smuzhiyun     seq_puts(m, "\nController Events:\n");
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun     for (id = -1;;) {
531*4882a593Smuzhiyun         id = gdth_read_event(ha, id, estr);
532*4882a593Smuzhiyun         if (estr->event_source == 0)
533*4882a593Smuzhiyun             break;
534*4882a593Smuzhiyun         if (estr->event_data.eu.driver.ionode == ha->hanum &&
535*4882a593Smuzhiyun             estr->event_source == ES_ASYNC) {
536*4882a593Smuzhiyun             gdth_log_event(&estr->event_data, hrec);
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	    /*
539*4882a593Smuzhiyun 	     * Elapsed seconds subtraction with unsigned operands is
540*4882a593Smuzhiyun 	     * safe from wrap around in year 2106.  Executes as:
541*4882a593Smuzhiyun 	     * operand a + (2's complement operand b) + 1
542*4882a593Smuzhiyun 	     */
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun 	    sec = (int)((u32)ktime_get_real_seconds() - estr->first_stamp);
545*4882a593Smuzhiyun             if (sec < 0) sec = 0;
546*4882a593Smuzhiyun             seq_printf(m," date- %02d:%02d:%02d\t%s\n",
547*4882a593Smuzhiyun                            sec/3600, sec%3600/60, sec%60, hrec);
548*4882a593Smuzhiyun         }
549*4882a593Smuzhiyun         if (id == -1)
550*4882a593Smuzhiyun             break;
551*4882a593Smuzhiyun     }
552*4882a593Smuzhiyun stop_output:
553*4882a593Smuzhiyun     rc = 0;
554*4882a593Smuzhiyun free_fail:
555*4882a593Smuzhiyun     kfree(gdtcmd);
556*4882a593Smuzhiyun     kfree(estr);
557*4882a593Smuzhiyun     return rc;
558*4882a593Smuzhiyun }
559*4882a593Smuzhiyun 
gdth_wait_completion(gdth_ha_str * ha,int busnum,int id)560*4882a593Smuzhiyun static void gdth_wait_completion(gdth_ha_str *ha, int busnum, int id)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun     unsigned long flags;
563*4882a593Smuzhiyun     int i;
564*4882a593Smuzhiyun     struct scsi_cmnd *scp;
565*4882a593Smuzhiyun     struct gdth_cmndinfo *cmndinfo;
566*4882a593Smuzhiyun     u8 b, t;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun     spin_lock_irqsave(&ha->smp_lock, flags);
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun     for (i = 0; i < GDTH_MAXCMDS; ++i) {
571*4882a593Smuzhiyun         scp = ha->cmd_tab[i].cmnd;
572*4882a593Smuzhiyun         cmndinfo = gdth_cmnd_priv(scp);
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun         b = scp->device->channel;
575*4882a593Smuzhiyun         t = scp->device->id;
576*4882a593Smuzhiyun         if (!SPECIAL_SCP(scp) && t == (u8)id &&
577*4882a593Smuzhiyun             b == (u8)busnum) {
578*4882a593Smuzhiyun             cmndinfo->wait_for_completion = 0;
579*4882a593Smuzhiyun             spin_unlock_irqrestore(&ha->smp_lock, flags);
580*4882a593Smuzhiyun             while (!cmndinfo->wait_for_completion)
581*4882a593Smuzhiyun                 barrier();
582*4882a593Smuzhiyun             spin_lock_irqsave(&ha->smp_lock, flags);
583*4882a593Smuzhiyun         }
584*4882a593Smuzhiyun     }
585*4882a593Smuzhiyun     spin_unlock_irqrestore(&ha->smp_lock, flags);
586*4882a593Smuzhiyun }
587