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