1 /* gdth_proc.c
2 * $Id: gdth_proc.c,v 1.42 2004/03/05 15:50:20 achim Exp $
3 */
4
5 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
6 #include <linux/completion.h>
7 #endif
8
9 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
gdth_proc_info(struct Scsi_Host * host,char * buffer,char ** start,off_t offset,int length,int inout)10 int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,
11 int inout)
12 {
13 int hanum,busnum;
14
15 TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
16 length,(int)offset,inout));
17
18 hanum = NUMDATA(host)->hanum;
19 busnum= NUMDATA(host)->busnum;
20
21 if (inout)
22 return(gdth_set_info(buffer,length,host,hanum,busnum));
23 else
24 return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum));
25 }
26 #else
gdth_proc_info(char * buffer,char ** start,off_t offset,int length,int hostno,int inout)27 int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno,
28 int inout)
29 {
30 int hanum,busnum,i;
31
32 TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
33 length,(int)offset,inout));
34
35 for (i = 0; i < gdth_ctr_vcount; ++i) {
36 if (gdth_ctr_vtab[i]->host_no == hostno)
37 break;
38 }
39 if (i == gdth_ctr_vcount)
40 return(-EINVAL);
41
42 hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
43 busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
44
45 if (inout)
46 return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum));
47 else
48 return(gdth_get_info(buffer,start,offset,length,
49 gdth_ctr_vtab[i],hanum,busnum));
50 }
51 #endif
52
gdth_set_info(char * buffer,int length,struct Scsi_Host * host,int hanum,int busnum)53 static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
54 int hanum,int busnum)
55 {
56 int ret_val = -EINVAL;
57 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
58 Scsi_Request *scp;
59 Scsi_Device *sdev;
60 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
61 Scsi_Cmnd *scp;
62 Scsi_Device *sdev;
63 #else
64 Scsi_Cmnd scp;
65 Scsi_Device sdev;
66 #endif
67 TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
68
69 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
70 sdev = scsi_get_host_dev(host);
71 scp = scsi_allocate_request(sdev, GFP_KERNEL);
72 if (!scp)
73 return -ENOMEM;
74 scp->sr_cmd_len = 12;
75 scp->sr_use_sg = 0;
76 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
77 sdev = scsi_get_host_dev(host);
78 scp = scsi_allocate_device(sdev, 1, FALSE);
79 if (!scp)
80 return -ENOMEM;
81 scp->cmd_len = 12;
82 scp->use_sg = 0;
83 #else
84 memset(&sdev,0,sizeof(Scsi_Device));
85 memset(&scp, 0,sizeof(Scsi_Cmnd));
86 sdev.host = scp.host = host;
87 sdev.id = scp.target = sdev.host->this_id;
88 scp.device = &sdev;
89 #endif
90
91 if (length >= 4) {
92 if (strncmp(buffer,"gdth",4) == 0) {
93 buffer += 5;
94 length -= 5;
95 ret_val = gdth_set_asc_info( buffer, length, hanum, scp );
96 }
97 }
98 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
99 scsi_release_request(scp);
100 scsi_free_host_dev(sdev);
101 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
102 scsi_release_command(scp);
103 scsi_free_host_dev(sdev);
104 #endif
105 return ret_val;
106 }
107
108 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
gdth_set_asc_info(char * buffer,int length,int hanum,Scsi_Request * scp)109 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp)
110 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
111 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
112 #else
113 static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
114 #endif
115 {
116 int orig_length, drive, wb_mode;
117 int i, found;
118 gdth_ha_str *ha;
119 gdth_cmd_str gdtcmd;
120 gdth_cpar_str *pcpar;
121 ulong64 paddr;
122
123 char cmnd[MAX_COMMAND_SIZE];
124 memset(cmnd, 0xff, 12);
125 memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
126
127 TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
128 ha = HADATA(gdth_ctr_tab[hanum]);
129 orig_length = length + 5;
130 drive = -1;
131 wb_mode = 0;
132 found = FALSE;
133
134 if (length >= 5 && strncmp(buffer,"flush",5)==0) {
135 buffer += 6;
136 length -= 6;
137 if (length && *buffer>='0' && *buffer<='9') {
138 drive = (int)(*buffer-'0');
139 ++buffer; --length;
140 if (length && *buffer>='0' && *buffer<='9') {
141 drive = drive*10 + (int)(*buffer-'0');
142 ++buffer; --length;
143 }
144 printk("GDT: Flushing host drive %d .. ",drive);
145 } else {
146 printk("GDT: Flushing all host drives .. ");
147 }
148 for (i = 0; i < MAX_HDRIVES; ++i) {
149 if (ha->hdr[i].present) {
150 if (drive != -1 && i != drive)
151 continue;
152 found = TRUE;
153 gdtcmd.Service = CACHESERVICE;
154 gdtcmd.OpCode = GDT_FLUSH;
155 if (ha->cache_feat & GDT_64BIT) {
156 gdtcmd.u.cache64.DeviceNo = i;
157 gdtcmd.u.cache64.BlockNo = 1;
158 } else {
159 gdtcmd.u.cache.DeviceNo = i;
160 gdtcmd.u.cache.BlockNo = 1;
161 }
162 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
163 gdth_do_req(scp, &gdtcmd, cmnd, 30);
164 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
165 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
166 #else
167 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
168 #endif
169 }
170 }
171 if (!found)
172 printk("\nNo host drive found !\n");
173 else
174 printk("Done.\n");
175 return(orig_length);
176 }
177
178 if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
179 buffer += 8;
180 length -= 8;
181 printk("GDT: Disabling write back permanently .. ");
182 wb_mode = 1;
183 } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
184 buffer += 7;
185 length -= 7;
186 printk("GDT: Enabling write back permanently .. ");
187 wb_mode = 2;
188 } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
189 buffer += 7;
190 length -= 7;
191 printk("GDT: Disabling write back commands .. ");
192 if (ha->cache_feat & GDT_WR_THROUGH) {
193 gdth_write_through = TRUE;
194 printk("Done.\n");
195 } else {
196 printk("Not supported !\n");
197 }
198 return(orig_length);
199 } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
200 buffer += 6;
201 length -= 6;
202 printk("GDT: Enabling write back commands .. ");
203 gdth_write_through = FALSE;
204 printk("Done.\n");
205 return(orig_length);
206 }
207
208 if (wb_mode) {
209 if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr))
210 return(-EBUSY);
211 pcpar = (gdth_cpar_str *)ha->pscratch;
212 memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
213 gdtcmd.Service = CACHESERVICE;
214 gdtcmd.OpCode = GDT_IOCTL;
215 gdtcmd.u.ioctl.p_param = paddr;
216 gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
217 gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
218 gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
219 pcpar->write_back = wb_mode==1 ? 0:1;
220 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
221 gdth_do_req(scp, &gdtcmd, cmnd, 30);
222 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
223 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
224 #else
225 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
226 #endif
227 gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr);
228 printk("Done.\n");
229 return(orig_length);
230 }
231
232 printk("GDT: Unknown command: %s Length: %d\n",buffer,length);
233 return(-EINVAL);
234 }
235
gdth_get_info(char * buffer,char ** start,off_t offset,int length,struct Scsi_Host * host,int hanum,int busnum)236 static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
237 struct Scsi_Host *host,int hanum,int busnum)
238 {
239 int size = 0,len = 0;
240 off_t begin = 0,pos = 0;
241 gdth_ha_str *ha;
242 int id, i, j, k, sec, flag;
243 int no_mdrv = 0, drv_no, is_mirr;
244 ulong32 cnt;
245 ulong64 paddr;
246
247 gdth_cmd_str gdtcmd;
248 gdth_evt_str estr;
249 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
250 Scsi_Request *scp;
251 Scsi_Device *sdev;
252 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
253 Scsi_Cmnd *scp;
254 Scsi_Device *sdev;
255 #else
256 Scsi_Cmnd scp;
257 Scsi_Device sdev;
258 #endif
259 char hrec[161];
260 struct timeval tv;
261
262 char *buf;
263 gdth_dskstat_str *pds;
264 gdth_diskinfo_str *pdi;
265 gdth_arrayinf_str *pai;
266 gdth_defcnt_str *pdef;
267 gdth_cdrinfo_str *pcdi;
268 gdth_hget_str *phg;
269
270 char cmnd[MAX_COMMAND_SIZE];
271 memset(cmnd, 0xff, 12);
272 memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
273
274 TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
275 ha = HADATA(gdth_ctr_tab[hanum]);
276
277 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
278 sdev = scsi_get_host_dev(host);
279 scp = scsi_allocate_request(sdev, GFP_KERNEL);
280 if (!scp)
281 return -ENOMEM;
282 scp->sr_cmd_len = 12;
283 scp->sr_use_sg = 0;
284 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
285 sdev = scsi_get_host_dev(host);
286 scp = scsi_allocate_device(sdev, 1, FALSE);
287 if (!scp)
288 return -ENOMEM;
289 scp->cmd_len = 12;
290 scp->use_sg = 0;
291 #else
292 memset(&sdev,0,sizeof(Scsi_Device));
293 memset(&scp, 0,sizeof(Scsi_Cmnd));
294 sdev.host = scp.host = host;
295 sdev.id = scp.target = sdev.host->this_id;
296 scp.device = &sdev;
297 #endif
298
299
300 /* request is i.e. "cat /proc/scsi/gdth/0" */
301 /* format: %-15s\t%-10s\t%-15s\t%s */
302 /* driver parameters */
303 size = sprintf(buffer+len,"Driver Parameters:\n");
304 len += size; pos = begin + len;
305 if (reserve_list[0] == 0xff)
306 strcpy(hrec, "--");
307 else {
308 sprintf(hrec, "%d", reserve_list[0]);
309 for (i = 1; i < MAX_RES_ARGS; i++) {
310 if (reserve_list[i] == 0xff)
311 break;
312 sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
313 }
314 }
315 size = sprintf(buffer+len,
316 " reserve_mode: \t%d \treserve_list: \t%s\n",
317 reserve_mode, hrec);
318 len += size; pos = begin + len;
319 size = sprintf(buffer+len,
320 " max_ids: \t%-3d \thdr_channel: \t%d\n",
321 max_ids, hdr_channel);
322 len += size; pos = begin + len;
323
324 /* controller information */
325 size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
326 len += size; pos = begin + len;
327 if (virt_ctr)
328 sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
329 else
330 strcpy(hrec, ha->binfo.type_string);
331 size = sprintf(buffer+len,
332 " Number: \t%d \tName: \t%s\n",
333 hanum, hrec);
334 len += size; pos = begin + len;
335
336 if (ha->more_proc)
337 sprintf(hrec, "%d.%02d.%02d-%c%03X",
338 (unchar)(ha->binfo.upd_fw_ver>>24),
339 (unchar)(ha->binfo.upd_fw_ver>>16),
340 (unchar)(ha->binfo.upd_fw_ver),
341 ha->bfeat.raid ? 'R':'N',
342 ha->binfo.upd_revision);
343 else
344 sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
345 (unchar)(ha->cpar.version));
346
347 size = sprintf(buffer+len,
348 " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n",
349 GDTH_VERSION_STR, hrec);
350 len += size; pos = begin + len;
351
352 if (ha->more_proc) {
353 /* more information: 1. about controller */
354 size = sprintf(buffer+len,
355 " Serial No.: \t0x%8X\tCache RAM size:\t%d KB\n",
356 ha->binfo.ser_no, ha->binfo.memsize / 1024);
357 len += size; pos = begin + len;
358 }
359
360 #ifdef GDTH_DMA_STATISTICS
361 /* controller statistics */
362 size = sprintf(buffer+len,"\nController Statistics:\n");
363 len += size; pos = begin + len;
364 size = sprintf(buffer+len,
365 " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n",
366 ha->dma32_cnt, ha->dma64_cnt);
367 len += size; pos = begin + len;
368 #endif
369
370 if (pos < offset) {
371 len = 0;
372 begin = pos;
373 }
374 if (pos > offset + length)
375 goto stop_output;
376
377 if (ha->more_proc) {
378 /* more information: 2. about physical devices */
379 size = sprintf(buffer+len,"\nPhysical Devices:");
380 len += size; pos = begin + len;
381 flag = FALSE;
382
383 buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
384 if (!buf)
385 goto stop_output;
386 for (i = 0; i < ha->bus_cnt; ++i) {
387 /* 2.a statistics (and retries/reassigns) */
388 TRACE2(("pdr_statistics() chn %d\n",i));
389 pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
390 gdtcmd.Service = CACHESERVICE;
391 gdtcmd.OpCode = GDT_IOCTL;
392 gdtcmd.u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
393 gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4;
394 gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
395 gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
396 pds->bid = ha->raw[i].local_no;
397 pds->first = 0;
398 pds->entries = ha->raw[i].pdev_cnt;
399 cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
400 sizeof(pds->list[0]);
401 if (pds->entries > cnt)
402 pds->entries = cnt;
403 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
404 gdth_do_req(scp, &gdtcmd, cmnd, 30);
405 if (scp->sr_command->SCp.Status != S_OK)
406 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
407 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
408 if (scp->SCp.Status != S_OK)
409 #else
410 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
411 if (scp.SCp.Status != S_OK)
412 #endif
413 {
414 pds->count = 0;
415 }
416
417 /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
418 for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
419 /* 2.b drive info */
420 TRACE2(("scsi_drv_info() chn %d dev %d\n",
421 i, ha->raw[i].id_list[j]));
422 pdi = (gdth_diskinfo_str *)buf;
423 gdtcmd.Service = CACHESERVICE;
424 gdtcmd.OpCode = GDT_IOCTL;
425 gdtcmd.u.ioctl.p_param = paddr;
426 gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str);
427 gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
428 gdtcmd.u.ioctl.channel =
429 ha->raw[i].address | ha->raw[i].id_list[j];
430 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
431 gdth_do_req(scp, &gdtcmd, cmnd, 30);
432 if (scp->sr_command->SCp.Status == S_OK)
433 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
434 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
435 if (scp->SCp.Status == S_OK)
436 #else
437 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
438 if (scp.SCp.Status == S_OK)
439 #endif
440 {
441 strncpy(hrec,pdi->vendor,8);
442 strncpy(hrec+8,pdi->product,16);
443 strncpy(hrec+24,pdi->revision,4);
444 hrec[28] = 0;
445 size = sprintf(buffer+len,
446 "\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n",
447 'A'+i,pdi->target_id,pdi->lun,hrec);
448 len += size; pos = begin + len;
449 flag = TRUE;
450 pdi->no_ldrive &= 0xffff;
451 if (pdi->no_ldrive == 0xffff)
452 strcpy(hrec,"--");
453 else
454 sprintf(hrec,"%d",pdi->no_ldrive);
455 size = sprintf(buffer+len,
456 " Capacity [MB]:\t%-6d \tTo Log. Drive: \t%s\n",
457 pdi->blkcnt/(1024*1024/pdi->blksize),
458 hrec);
459 len += size; pos = begin + len;
460 } else {
461 pdi->devtype = 0xff;
462 }
463
464 if (pdi->devtype == 0) {
465 /* search retries/reassigns */
466 for (k = 0; k < pds->count; ++k) {
467 if (pds->list[k].tid == pdi->target_id &&
468 pds->list[k].lun == pdi->lun) {
469 size = sprintf(buffer+len,
470 " Retries: \t%-6d \tReassigns: \t%d\n",
471 pds->list[k].retries,
472 pds->list[k].reassigns);
473 len += size; pos = begin + len;
474 break;
475 }
476 }
477 /* 2.c grown defects */
478 TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
479 i, ha->raw[i].id_list[j]));
480 pdef = (gdth_defcnt_str *)buf;
481 gdtcmd.Service = CACHESERVICE;
482 gdtcmd.OpCode = GDT_IOCTL;
483 gdtcmd.u.ioctl.p_param = paddr;
484 gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str);
485 gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
486 gdtcmd.u.ioctl.channel =
487 ha->raw[i].address | ha->raw[i].id_list[j];
488 pdef->sddc_type = 0x08;
489 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
490 gdth_do_req(scp, &gdtcmd, cmnd, 30);
491 if (scp->sr_command->SCp.Status == S_OK)
492 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
493 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
494 if (scp->SCp.Status == S_OK)
495 #else
496 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
497 if (scp.SCp.Status == S_OK)
498 #endif
499 {
500 size = sprintf(buffer+len,
501 " Grown Defects:\t%d\n",
502 pdef->sddc_cnt);
503 len += size; pos = begin + len;
504 }
505 }
506 if (pos < offset) {
507 len = 0;
508 begin = pos;
509 }
510 if (pos > offset + length)
511 goto stop_output;
512 }
513 }
514 gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
515
516 if (!flag) {
517 size = sprintf(buffer+len, "\n --\n");
518 len += size; pos = begin + len;
519 }
520
521 /* 3. about logical drives */
522 size = sprintf(buffer+len,"\nLogical Drives:");
523 len += size; pos = begin + len;
524 flag = FALSE;
525
526 buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
527 if (!buf)
528 goto stop_output;
529 for (i = 0; i < MAX_LDRIVES; ++i) {
530 if (!ha->hdr[i].is_logdrv)
531 continue;
532 drv_no = i;
533 j = k = 0;
534 is_mirr = FALSE;
535 do {
536 /* 3.a log. drive info */
537 TRACE2(("cache_drv_info() drive no %d\n",drv_no));
538 pcdi = (gdth_cdrinfo_str *)buf;
539 gdtcmd.Service = CACHESERVICE;
540 gdtcmd.OpCode = GDT_IOCTL;
541 gdtcmd.u.ioctl.p_param = paddr;
542 gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
543 gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
544 gdtcmd.u.ioctl.channel = drv_no;
545 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
546 gdth_do_req(scp, &gdtcmd, cmnd, 30);
547 if (scp->sr_command->SCp.Status != S_OK)
548 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
549 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
550 if (scp->SCp.Status != S_OK)
551 #else
552 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
553 if (scp.SCp.Status != S_OK)
554 #endif
555 {
556 break;
557 }
558 pcdi->ld_dtype >>= 16;
559 j++;
560 if (pcdi->ld_dtype > 2) {
561 strcpy(hrec, "missing");
562 } else if (pcdi->ld_error & 1) {
563 strcpy(hrec, "fault");
564 } else if (pcdi->ld_error & 2) {
565 strcpy(hrec, "invalid");
566 k++; j--;
567 } else {
568 strcpy(hrec, "ok");
569 }
570
571 if (drv_no == i) {
572 size = sprintf(buffer+len,
573 "\n Number: \t%-2d \tStatus: \t%s\n",
574 drv_no, hrec);
575 len += size; pos = begin + len;
576 flag = TRUE;
577 no_mdrv = pcdi->cd_ldcnt;
578 if (no_mdrv > 1 || pcdi->ld_slave != -1) {
579 is_mirr = TRUE;
580 strcpy(hrec, "RAID-1");
581 } else if (pcdi->ld_dtype == 0) {
582 strcpy(hrec, "Disk");
583 } else if (pcdi->ld_dtype == 1) {
584 strcpy(hrec, "RAID-0");
585 } else if (pcdi->ld_dtype == 2) {
586 strcpy(hrec, "Chain");
587 } else {
588 strcpy(hrec, "???");
589 }
590 size = sprintf(buffer+len,
591 " Capacity [MB]:\t%-6d \tType: \t%s\n",
592 pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
593 hrec);
594 len += size; pos = begin + len;
595 } else {
596 size = sprintf(buffer+len,
597 " Slave Number: \t%-2d \tStatus: \t%s\n",
598 drv_no & 0x7fff, hrec);
599 len += size; pos = begin + len;
600 }
601 drv_no = pcdi->ld_slave;
602 if (pos < offset) {
603 len = 0;
604 begin = pos;
605 }
606 if (pos > offset + length)
607 goto stop_output;
608 } while (drv_no != -1);
609
610 if (is_mirr) {
611 size = sprintf(buffer+len,
612 " Missing Drv.: \t%-2d \tInvalid Drv.: \t%d\n",
613 no_mdrv - j - k, k);
614 len += size; pos = begin + len;
615 }
616
617 if (!ha->hdr[i].is_arraydrv)
618 strcpy(hrec, "--");
619 else
620 sprintf(hrec, "%d", ha->hdr[i].master_no);
621 size = sprintf(buffer+len,
622 " To Array Drv.:\t%s\n", hrec);
623 len += size; pos = begin + len;
624 if (pos < offset) {
625 len = 0;
626 begin = pos;
627 }
628 if (pos > offset + length)
629 goto stop_output;
630 }
631 gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
632
633 if (!flag) {
634 size = sprintf(buffer+len, "\n --\n");
635 len += size; pos = begin + len;
636 }
637
638 /* 4. about array drives */
639 size = sprintf(buffer+len,"\nArray Drives:");
640 len += size; pos = begin + len;
641 flag = FALSE;
642
643 buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
644 if (!buf)
645 goto stop_output;
646 for (i = 0; i < MAX_LDRIVES; ++i) {
647 if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
648 continue;
649 /* 4.a array drive info */
650 TRACE2(("array_info() drive no %d\n",i));
651 pai = (gdth_arrayinf_str *)buf;
652 gdtcmd.Service = CACHESERVICE;
653 gdtcmd.OpCode = GDT_IOCTL;
654 gdtcmd.u.ioctl.p_param = paddr;
655 gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
656 gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
657 gdtcmd.u.ioctl.channel = i;
658 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
659 gdth_do_req(scp, &gdtcmd, cmnd, 30);
660 if (scp->sr_command->SCp.Status == S_OK)
661 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
662 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
663 if (scp->SCp.Status == S_OK)
664 #else
665 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
666 if (scp.SCp.Status == S_OK)
667 #endif
668 {
669 if (pai->ai_state == 0)
670 strcpy(hrec, "idle");
671 else if (pai->ai_state == 2)
672 strcpy(hrec, "build");
673 else if (pai->ai_state == 4)
674 strcpy(hrec, "ready");
675 else if (pai->ai_state == 6)
676 strcpy(hrec, "fail");
677 else if (pai->ai_state == 8 || pai->ai_state == 10)
678 strcpy(hrec, "rebuild");
679 else
680 strcpy(hrec, "error");
681 if (pai->ai_ext_state & 0x10)
682 strcat(hrec, "/expand");
683 else if (pai->ai_ext_state & 0x1)
684 strcat(hrec, "/patch");
685 size = sprintf(buffer+len,
686 "\n Number: \t%-2d \tStatus: \t%s\n",
687 i,hrec);
688 len += size; pos = begin + len;
689 flag = TRUE;
690
691 if (pai->ai_type == 0)
692 strcpy(hrec, "RAID-0");
693 else if (pai->ai_type == 4)
694 strcpy(hrec, "RAID-4");
695 else if (pai->ai_type == 5)
696 strcpy(hrec, "RAID-5");
697 else
698 strcpy(hrec, "RAID-10");
699 size = sprintf(buffer+len,
700 " Capacity [MB]:\t%-6d \tType: \t%s\n",
701 pai->ai_size/(1024*1024/pai->ai_secsize),
702 hrec);
703 len += size; pos = begin + len;
704 if (pos < offset) {
705 len = 0;
706 begin = pos;
707 }
708 if (pos > offset + length)
709 goto stop_output;
710 }
711 }
712 gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
713
714 if (!flag) {
715 size = sprintf(buffer+len, "\n --\n");
716 len += size; pos = begin + len;
717 }
718
719 /* 5. about host drives */
720 size = sprintf(buffer+len,"\nHost Drives:");
721 len += size; pos = begin + len;
722 flag = FALSE;
723
724 buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
725 if (!buf)
726 goto stop_output;
727 for (i = 0; i < MAX_LDRIVES; ++i) {
728 if (!ha->hdr[i].is_logdrv ||
729 (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
730 continue;
731 /* 5.a get host drive list */
732 TRACE2(("host_get() drv_no %d\n",i));
733 phg = (gdth_hget_str *)buf;
734 gdtcmd.Service = CACHESERVICE;
735 gdtcmd.OpCode = GDT_IOCTL;
736 gdtcmd.u.ioctl.p_param = paddr;
737 gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str);
738 gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
739 gdtcmd.u.ioctl.channel = i;
740 phg->entries = MAX_HDRIVES;
741 phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]);
742 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
743 gdth_do_req(scp, &gdtcmd, cmnd, 30);
744 if (scp->sr_command->SCp.Status != S_OK)
745 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
746 gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
747 if (scp->SCp.Status != S_OK)
748 #else
749 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
750 if (scp.SCp.Status != S_OK)
751 #endif
752 {
753 ha->hdr[i].ldr_no = i;
754 ha->hdr[i].rw_attribs = 0;
755 ha->hdr[i].start_sec = 0;
756 } else {
757 for (j = 0; j < phg->entries; ++j) {
758 k = phg->entry[j].host_drive;
759 if (k >= MAX_LDRIVES)
760 continue;
761 ha->hdr[k].ldr_no = phg->entry[j].log_drive;
762 ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
763 ha->hdr[k].start_sec = phg->entry[j].start_sec;
764 }
765 }
766 }
767 gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
768
769 for (i = 0; i < MAX_HDRIVES; ++i) {
770 if (!(ha->hdr[i].present))
771 continue;
772
773 size = sprintf(buffer+len,
774 "\n Number: \t%-2d \tArr/Log. Drive:\t%d\n",
775 i, ha->hdr[i].ldr_no);
776 len += size; pos = begin + len;
777 flag = TRUE;
778
779 size = sprintf(buffer+len,
780 " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n",
781 (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
782 len += size; pos = begin + len;
783 if (pos < offset) {
784 len = 0;
785 begin = pos;
786 }
787 if (pos > offset + length)
788 goto stop_output;
789 }
790
791 if (!flag) {
792 size = sprintf(buffer+len, "\n --\n");
793 len += size; pos = begin + len;
794 }
795 }
796
797 /* controller events */
798 size = sprintf(buffer+len,"\nController Events:\n");
799 len += size; pos = begin + len;
800
801 for (id = -1;;) {
802 id = gdth_read_event(ha, id, &estr);
803 if (estr.event_source == 0)
804 break;
805 if (estr.event_data.eu.driver.ionode == hanum &&
806 estr.event_source == ES_ASYNC) {
807 gdth_log_event(&estr.event_data, hrec);
808 do_gettimeofday(&tv);
809 sec = (int)(tv.tv_sec - estr.first_stamp);
810 if (sec < 0) sec = 0;
811 size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
812 sec/3600, sec%3600/60, sec%60, hrec);
813 len += size; pos = begin + len;
814 if (pos < offset) {
815 len = 0;
816 begin = pos;
817 }
818 if (pos > offset + length)
819 goto stop_output;
820 }
821 if (id == -1)
822 break;
823 }
824
825 stop_output:
826 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
827 scsi_release_request(scp);
828 scsi_free_host_dev(sdev);
829 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
830 scsi_release_command(scp);
831 scsi_free_host_dev(sdev);
832 #endif
833 *start = buffer +(offset-begin);
834 len -= (offset-begin);
835 if (len > length)
836 len = length;
837 TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n",
838 len,(int)pos,(int)begin,(int)offset,length,size));
839 return(len);
840 }
841
842
843 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
gdth_do_req(Scsi_Request * scp,gdth_cmd_str * gdtcmd,char * cmnd,int timeout)844 static void gdth_do_req(Scsi_Request *scp, gdth_cmd_str *gdtcmd,
845 char *cmnd, int timeout)
846 {
847 unsigned bufflen;
848 DECLARE_COMPLETION(wait);
849
850 TRACE2(("gdth_do_req()\n"));
851 if (gdtcmd != NULL) {
852 bufflen = sizeof(gdth_cmd_str);
853 } else {
854 bufflen = 0;
855 }
856 scp->sr_request->rq_status = RQ_SCSI_BUSY;
857 scp->sr_request->waiting = &wait;
858 scsi_do_req(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
859 wait_for_completion(&wait);
860 }
861
862 #else
gdth_do_cmd(Scsi_Cmnd * scp,gdth_cmd_str * gdtcmd,char * cmnd,int timeout)863 static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd,
864 char *cmnd, int timeout)
865 {
866 unsigned bufflen;
867 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
868 DECLARE_COMPLETION(wait);
869 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
870 DECLARE_MUTEX_LOCKED(sem);
871 #else
872 struct semaphore sem = MUTEX_LOCKED;
873 #endif
874
875 TRACE2(("gdth_do_cmd()\n"));
876 if (gdtcmd != NULL) {
877 scp->SCp.this_residual = IOCTL_PRI;
878 bufflen = sizeof(gdth_cmd_str);
879 } else {
880 scp->SCp.this_residual = DEFAULT_PRI;
881 bufflen = 0;
882 }
883 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
884 scp->request.rq_status = RQ_SCSI_BUSY;
885 scp->request.waiting = &wait;
886 scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
887 wait_for_completion(&wait);
888 #else
889 scp->request.sem = &sem;
890 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
891 scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
892 #else
893 spin_lock_irq(&io_request_lock);
894 scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
895 spin_unlock_irq(&io_request_lock);
896 #endif
897 down(&sem);
898 #endif
899 }
900 #endif
901
gdth_scsi_done(Scsi_Cmnd * scp)902 void gdth_scsi_done(Scsi_Cmnd *scp)
903 {
904 TRACE2(("gdth_scsi_done()\n"));
905
906 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
907 scp->request->rq_status = RQ_SCSI_DONE;
908 if (scp->request->waiting != NULL)
909 complete(scp->request->waiting);
910 #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
911 scp->request.rq_status = RQ_SCSI_DONE;
912 if (scp->request.waiting != NULL)
913 complete(scp->request.waiting);
914 #else
915 scp->request.rq_status = RQ_SCSI_DONE;
916 if (scp->request.sem != NULL)
917 up(scp->request.sem);
918 #endif
919 }
920
gdth_ioctl_alloc(int hanum,int size,int scratch,ulong64 * paddr)921 static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
922 ulong64 *paddr)
923 {
924 gdth_ha_str *ha;
925 ulong flags;
926 char *ret_val;
927
928 if (size == 0)
929 return NULL;
930
931 ha = HADATA(gdth_ctr_tab[hanum]);
932 GDTH_LOCK_HA(ha, flags);
933
934 if (!ha->scratch_busy && size <= GDTH_SCRATCH) {
935 ha->scratch_busy = TRUE;
936 ret_val = ha->pscratch;
937 *paddr = ha->scratch_phys;
938 } else if (scratch) {
939 ret_val = NULL;
940 } else {
941 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
942 dma_addr_t dma_addr;
943
944 ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr);
945 *paddr = dma_addr;
946 #else
947 ret_val = scsi_init_malloc(size, GFP_ATOMIC | GFP_DMA);
948 if (ret_val)
949 *paddr = virt_to_bus(ret_val);
950 #endif
951 }
952
953 GDTH_UNLOCK_HA(ha, flags);
954 return ret_val;
955 }
956
gdth_ioctl_free(int hanum,int size,char * buf,ulong64 paddr)957 static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
958 {
959 gdth_ha_str *ha;
960 ulong flags;
961
962 ha = HADATA(gdth_ctr_tab[hanum]);
963 GDTH_LOCK_HA(ha, flags);
964
965 if (buf == ha->pscratch) {
966 ha->scratch_busy = FALSE;
967 } else {
968 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
969 pci_free_consistent(ha->pdev, size, buf, paddr);
970 #else
971 scsi_init_free((void *)buf, size);
972 #endif
973 }
974
975 GDTH_UNLOCK_HA(ha, flags);
976 }
977
978 #ifdef GDTH_IOCTL_PROC
gdth_ioctl_check_bin(int hanum,ushort size)979 static int gdth_ioctl_check_bin(int hanum, ushort size)
980 {
981 gdth_ha_str *ha;
982 ulong flags;
983 int ret_val;
984
985 ha = HADATA(gdth_ctr_tab[hanum]);
986 GDTH_LOCK_HA(ha, flags);
987
988 ret_val = FALSE;
989 if (ha->scratch_busy) {
990 if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size)
991 ret_val = TRUE;
992 }
993 GDTH_UNLOCK_HA(ha, flags);
994 return ret_val;
995 }
996 #endif
997
gdth_wait_completion(int hanum,int busnum,int id)998 static void gdth_wait_completion(int hanum, int busnum, int id)
999 {
1000 gdth_ha_str *ha;
1001 ulong flags;
1002 int i;
1003 Scsi_Cmnd *scp;
1004 unchar b, t;
1005
1006 ha = HADATA(gdth_ctr_tab[hanum]);
1007 GDTH_LOCK_HA(ha, flags);
1008
1009 for (i = 0; i < GDTH_MAXCMDS; ++i) {
1010 scp = ha->cmd_tab[i].cmnd;
1011 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1012 b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
1013 t = scp->device->id;
1014 #else
1015 b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1016 t = scp->target;
1017 #endif
1018 if (!SPECIAL_SCP(scp) && t == (unchar)id &&
1019 b == (unchar)busnum) {
1020 scp->SCp.have_data_in = 0;
1021 GDTH_UNLOCK_HA(ha, flags);
1022 while (!scp->SCp.have_data_in)
1023 barrier();
1024 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1025 GDTH_LOCK_SCSI_DONE(scp->device->host, flags);
1026 scp->scsi_done(scp);
1027 GDTH_UNLOCK_SCSI_DONE(scp->device->host, flags);
1028 #else
1029 GDTH_LOCK_SCSI_DONE(flags);
1030 scp->scsi_done(scp);
1031 GDTH_UNLOCK_SCSI_DONE(flags);
1032 #endif
1033 GDTH_LOCK_HA(ha, flags);
1034 }
1035 }
1036 GDTH_UNLOCK_HA(ha, flags);
1037 }
1038
gdth_stop_timeout(int hanum,int busnum,int id)1039 static void gdth_stop_timeout(int hanum, int busnum, int id)
1040 {
1041 gdth_ha_str *ha;
1042 ulong flags;
1043 Scsi_Cmnd *scp;
1044 unchar b, t;
1045
1046 ha = HADATA(gdth_ctr_tab[hanum]);
1047 GDTH_LOCK_HA(ha, flags);
1048
1049 for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
1050 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1051 b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
1052 t = scp->device->id;
1053 #else
1054 b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1055 t = scp->target;
1056 #endif
1057 if (t == (unchar)id && b == (unchar)busnum) {
1058 TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
1059 scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
1060 }
1061 }
1062 GDTH_UNLOCK_HA(ha, flags);
1063 }
1064
gdth_start_timeout(int hanum,int busnum,int id)1065 static void gdth_start_timeout(int hanum, int busnum, int id)
1066 {
1067 gdth_ha_str *ha;
1068 ulong flags;
1069 Scsi_Cmnd *scp;
1070 unchar b, t;
1071
1072 ha = HADATA(gdth_ctr_tab[hanum]);
1073 GDTH_LOCK_HA(ha, flags);
1074
1075 for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
1076 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
1077 b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
1078 t = scp->device->id;
1079 #else
1080 b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel;
1081 t = scp->target;
1082 #endif
1083 if (t == (unchar)id && b == (unchar)busnum) {
1084 TRACE2(("gdth_start_timeout(): update_timeout()\n"));
1085 gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
1086 }
1087 }
1088 GDTH_UNLOCK_HA(ha, flags);
1089 }
1090
gdth_update_timeout(int hanum,Scsi_Cmnd * scp,int timeout)1091 static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
1092 {
1093 int oldto;
1094
1095 oldto = scp->timeout_per_command;
1096 scp->timeout_per_command = timeout;
1097
1098 if (timeout == 0) {
1099 del_timer(&scp->eh_timeout);
1100 scp->eh_timeout.data = (unsigned long) NULL;
1101 scp->eh_timeout.expires = 0;
1102 } else {
1103 if (scp->eh_timeout.data != (unsigned long) NULL)
1104 del_timer(&scp->eh_timeout);
1105 scp->eh_timeout.data = (unsigned long) scp;
1106 scp->eh_timeout.expires = jiffies + timeout;
1107 add_timer(&scp->eh_timeout);
1108 }
1109
1110 return oldto;
1111 }
1112