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