1/* gdth_proc.c 2 * $Id: gdth_proc.c,v 1.1.1.1 2008/10/15 03:26:52 james26_jang Exp $ 3 */ 4 5#include "gdth_ioctl.h" 6#if LINUX_VERSION_CODE >= 0x020407 7#include <linux/completion.h> 8#endif 9 10int gdth_proc_info(char *buffer,char **start,off_t offset,int length, 11 int hostno,int inout) 12{ 13 int hanum,busnum,i; 14 15 TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n", 16 length,hostno,(int)offset,inout)); 17 18 for (i=0; i<gdth_ctr_vcount; ++i) { 19 if (gdth_ctr_vtab[i]->host_no == hostno) 20 break; 21 } 22 if (i==gdth_ctr_vcount) 23 return(-EINVAL); 24 25 hanum = NUMDATA(gdth_ctr_vtab[i])->hanum; 26 busnum= NUMDATA(gdth_ctr_vtab[i])->busnum; 27 28 if (inout) 29 return(gdth_set_info(buffer,length,i,hanum,busnum)); 30 else 31 return(gdth_get_info(buffer,start,offset,length,i,hanum,busnum)); 32} 33 34static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum) 35{ 36 int ret_val; 37#if LINUX_VERSION_CODE >= 0x020322 38 Scsi_Cmnd *scp; 39 Scsi_Device *sdev; 40#else 41 Scsi_Cmnd scp; 42 Scsi_Device sdev; 43#endif 44 gdth_iowr_str *piowr; 45 46 TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum)); 47 piowr = (gdth_iowr_str *)buffer; 48 49#if LINUX_VERSION_CODE >= 0x020322 50 sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]); 51 scp = scsi_allocate_device(sdev, 1, FALSE); 52 if (!scp) 53 return -ENOMEM; 54 scp->cmd_len = 12; 55 scp->use_sg = 0; 56#else 57 memset(&sdev,0,sizeof(Scsi_Device)); 58 memset(&scp, 0,sizeof(Scsi_Cmnd)); 59 sdev.host = scp.host = gdth_ctr_vtab[vh]; 60 sdev.id = scp.target = sdev.host->this_id; 61 scp.device = &sdev; 62#endif 63 64 if (length >= 4) { 65 if (strncmp(buffer,"gdth",4) == 0) { 66 buffer += 5; 67 length -= 5; 68 ret_val = gdth_set_asc_info( buffer, length, hanum, scp ); 69 } else if (piowr->magic == GDTIOCTL_MAGIC) { 70 ret_val = gdth_set_bin_info( buffer, length, hanum, scp ); 71 } else { 72 printk("GDT: Wrong signature %x (%x required)!\n", 73 piowr->magic, GDTIOCTL_MAGIC); 74 if (piowr->magic > GDTIOCTL_MAGIC) 75 printk("GDT: Please update your driver.\n"); 76 else 77 printk("GDT: Please update your tool.\n"); 78 ret_val = -EINVAL; 79 } 80 } else { 81 ret_val = -EINVAL; 82 } 83#if LINUX_VERSION_CODE >= 0x020322 84 scsi_release_command(scp); 85 scsi_free_host_dev(sdev); 86#endif 87 return ret_val; 88} 89 90#if LINUX_VERSION_CODE >= 0x020322 91static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp) 92#else 93static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) 94#endif 95{ 96 int orig_length, drive, wb_mode; 97 int i, found; 98 gdth_ha_str *ha; 99 gdth_cmd_str gdtcmd; 100 gdth_cpar_str *pcpar; 101 102 char cmnd[MAX_COMMAND_SIZE]; 103 memset(cmnd, 0xff, 12); 104 memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); 105 106 TRACE2(("gdth_set_asc_info() ha %d\n",hanum)); 107 ha = HADATA(gdth_ctr_tab[hanum]); 108 orig_length = length + 5; 109 drive = -1; 110 wb_mode = 0; 111 found = FALSE; 112 113 if (length >= 5 && strncmp(buffer,"flush",5)==0) { 114 buffer += 6; 115 length -= 6; 116 if (length && *buffer>='0' && *buffer<='9') { 117 drive = (int)(*buffer-'0'); 118 ++buffer; --length; 119 if (length && *buffer>='0' && *buffer<='9') { 120 drive = drive*10 + (int)(*buffer-'0'); 121 ++buffer; --length; 122 } 123 printk("GDT: Flushing host drive %d .. ",drive); 124 } else { 125 printk("GDT: Flushing all host drives .. "); 126 } 127 for (i = 0; i < MAX_HDRIVES; ++i) { 128 if (ha->hdr[i].present) { 129 if (drive != -1 && i != drive) 130 continue; 131 found = TRUE; 132 gdtcmd.Service = CACHESERVICE; 133 gdtcmd.OpCode = GDT_FLUSH; 134 gdtcmd.u.cache.DeviceNo = i; 135 gdtcmd.u.cache.BlockNo = 1; 136#if LINUX_VERSION_CODE >= 0x020322 137 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 138#else 139 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 140#endif 141 } 142 } 143 if (!found) 144 printk("\nNo host drive found !\n"); 145 else 146 printk("Done.\n"); 147 return(orig_length); 148 } 149 150 if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) { 151 buffer += 8; 152 length -= 8; 153 printk("GDT: Disabling write back permanently .. "); 154 wb_mode = 1; 155 } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) { 156 buffer += 7; 157 length -= 7; 158 printk("GDT: Enabling write back permanently .. "); 159 wb_mode = 2; 160 } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) { 161 buffer += 7; 162 length -= 7; 163 printk("GDT: Disabling write back commands .. "); 164 if (ha->cache_feat & GDT_WR_THROUGH) { 165 gdth_write_through = TRUE; 166 printk("Done.\n"); 167 } else { 168 printk("Not supported !\n"); 169 } 170 return(orig_length); 171 } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) { 172 buffer += 6; 173 length -= 6; 174 printk("GDT: Enabling write back commands .. "); 175 gdth_write_through = FALSE; 176 printk("Done.\n"); 177 return(orig_length); 178 } 179 180 if (wb_mode) { 181 if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE)) 182 return(-EBUSY); 183 pcpar = (gdth_cpar_str *)ha->pscratch; 184 memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) ); 185 gdtcmd.Service = CACHESERVICE; 186 gdtcmd.OpCode = GDT_IOCTL; 187 gdtcmd.u.ioctl.p_param = virt_to_bus(pcpar); 188 gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str); 189 gdtcmd.u.ioctl.subfunc = CACHE_CONFIG; 190 gdtcmd.u.ioctl.channel = INVALID_CHANNEL; 191 pcpar->write_back = wb_mode==1 ? 0:1; 192#if LINUX_VERSION_CODE >= 0x020322 193 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 194#else 195 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 196#endif 197 gdth_ioctl_free(hanum, ha->pscratch); 198 printk("Done.\n"); 199 return(orig_length); 200 } 201 202 printk("GDT: Unknown command: %s Length: %d\n",buffer,length); 203 return(-EINVAL); 204} 205 206#if LINUX_VERSION_CODE >= 0x020322 207static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp) 208#else 209static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp) 210#endif 211{ 212 unchar i, j; 213 ushort k, hdr_cnt, status; 214 gdth_ha_str *ha; 215 gdth_iowr_str *piowr; 216 gdth_iord_str *piord; 217 gdth_cmd_str *pcmd; 218 gdth_evt_str *pevt; 219 ulong32 *ppadd, add_size, *ppadd2, add_size2, info; 220 ulong flags; 221 gdth_cmd_str gdtcmd; 222 int drv_cyls, drv_hds, drv_secs; 223 224 char cmnd[MAX_COMMAND_SIZE]; 225 memset(cmnd, 0xff, 12); 226 memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); 227 228 TRACE2(("gdth_set_bin_info() ha %d\n",hanum)); 229 ha = HADATA(gdth_ctr_tab[hanum]); 230 piowr = (gdth_iowr_str *)buffer; 231 piord = NULL; 232 pcmd = NULL; 233 ppadd = ppadd2 = NULL; 234 add_size = add_size2 = 0; 235 236 if (length < GDTOFFSOF(gdth_iowr_str,iu)) 237 return(-EINVAL); 238 239 switch (piowr->ioctl) { 240 case GDTIOCTL_GENERAL: 241 if (length < GDTOFFSOF(gdth_iowr_str,iu.general.data[0])) 242 return(-EINVAL); 243 pcmd = (gdth_cmd_str *)piowr->iu.general.command; 244 pcmd->Service = piowr->service; 245 if (pcmd->OpCode == GDT_IOCTL) { 246 ppadd = &pcmd->u.ioctl.p_param; 247 add_size = pcmd->u.ioctl.param_size; 248 } else if (piowr->service == CACHESERVICE) { 249 add_size = pcmd->u.cache.BlockCnt * SECTOR_SIZE; 250 if (ha->cache_feat & SCATTER_GATHER) { 251 ppadd = &pcmd->u.cache.sg_lst[0].sg_ptr; 252 pcmd->u.cache.DestAddr = 0xffffffff; 253 pcmd->u.cache.sg_lst[0].sg_len = add_size; 254 pcmd->u.cache.sg_canz = 1; 255 } else { 256 ppadd = &pcmd->u.cache.DestAddr; 257 pcmd->u.cache.sg_canz = 0; 258 } 259 } else if (piowr->service == SCSIRAWSERVICE) { 260 add_size = pcmd->u.raw.sdlen; 261 add_size2 = pcmd->u.raw.sense_len; 262 if (ha->raw_feat & SCATTER_GATHER) { 263 ppadd = &pcmd->u.raw.sg_lst[0].sg_ptr; 264 pcmd->u.raw.sdata = 0xffffffff; 265 pcmd->u.raw.sg_lst[0].sg_len = add_size; 266 pcmd->u.raw.sg_ranz = 1; 267 } else { 268 ppadd = &pcmd->u.raw.sdata; 269 pcmd->u.raw.sg_ranz = 0; 270 } 271 ppadd2 = &pcmd->u.raw.sense_data; 272 } else { 273 return(-EINVAL); 274 } 275 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str)+add_size+add_size2, 276 TRUE )) 277 return(-EBUSY); 278 piord = (gdth_iord_str *)ha->pscratch; 279 280 piord->size = sizeof(gdth_iord_str) + add_size + add_size2; 281 if (add_size > 0) { 282 memcpy(piord->iu.general.data, piowr->iu.general.data, add_size); 283 *ppadd = virt_to_bus(piord->iu.general.data); 284 } 285 if (add_size2 > 0) { 286 memcpy(piord->iu.general.data+add_size, piowr->iu.general.data, add_size2); 287 *ppadd2 = virt_to_bus(piord->iu.general.data+add_size); 288 } 289 /* do IOCTL */ 290#if LINUX_VERSION_CODE >= 0x020322 291 gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout); 292 piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; 293#else 294 gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout); 295 piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; 296#endif 297 break; 298 299 case GDTIOCTL_DRVERS: 300 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 301 return(-EBUSY); 302 piord = (gdth_iord_str *)ha->pscratch; 303 piord->size = sizeof(gdth_iord_str); 304 piord->status = S_OK; 305 piord->iu.drvers.version = (GDTH_VERSION<<8) | GDTH_SUBVERSION; 306 break; 307 308 case GDTIOCTL_CTRTYPE: 309 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 310 return(-EBUSY); 311 piord = (gdth_iord_str *)ha->pscratch; 312 piord->size = sizeof(gdth_iord_str); 313 piord->status = S_OK; 314 if (ha->type == GDT_ISA || ha->type == GDT_EISA) { 315 piord->iu.ctrtype.type = (unchar)((ha->stype>>20) - 0x10); 316 } else { 317 if (ha->type != GDT_PCIMPR) { 318 piord->iu.ctrtype.type = (unchar)((ha->stype<<4) + 6); 319 } else { 320 piord->iu.ctrtype.type = 321 (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe); 322 if (ha->stype >= 0x300) 323 piord->iu.ctrtype.ext_type = 0x6000 | ha->subdevice_id; 324 else 325 piord->iu.ctrtype.ext_type = 0x6000 | ha->stype; 326 } 327 piord->iu.ctrtype.device_id = ha->stype; 328 piord->iu.ctrtype.sub_device_id = ha->subdevice_id; 329 } 330 piord->iu.ctrtype.info = ha->brd_phys; 331 piord->iu.ctrtype.oem_id = ha->oem_id; 332 break; 333 334 case GDTIOCTL_CTRCNT: 335 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 336 return(-EBUSY); 337 piord = (gdth_iord_str *)ha->pscratch; 338 piord->size = sizeof(gdth_iord_str); 339 piord->status = S_OK; 340 piord->iu.ctrcnt.count = (ushort)gdth_ctr_count; 341 break; 342 343 case GDTIOCTL_OSVERS: 344 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 345 return(-EBUSY); 346 piord = (gdth_iord_str *)ha->pscratch; 347 piord->size = sizeof(gdth_iord_str); 348 piord->status = S_OK; 349 piord->iu.osvers.version = (unchar)(LINUX_VERSION_CODE >> 16); 350 piord->iu.osvers.subversion = (unchar)(LINUX_VERSION_CODE >> 8); 351 piord->iu.osvers.revision = (ushort)(LINUX_VERSION_CODE & 0xff); 352 break; 353 354 case GDTIOCTL_LOCKDRV: 355 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 356 return(-EBUSY); 357 piord = (gdth_iord_str *)ha->pscratch; 358 for (i = 0; i < piowr->iu.lockdrv.drive_cnt; ++i) { 359 j = piowr->iu.lockdrv.drives[i]; 360 if (j >= MAX_HDRIVES || !ha->hdr[j].present) 361 continue; 362 if (piowr->iu.lockdrv.lock) { 363 GDTH_LOCK_HA(ha, flags); 364 ha->hdr[j].lock = 1; 365 GDTH_UNLOCK_HA(ha, flags); 366 gdth_wait_completion( hanum, ha->bus_cnt, j ); 367 gdth_stop_timeout( hanum, ha->bus_cnt, j ); 368 } else { 369 GDTH_LOCK_HA(ha, flags); 370 ha->hdr[j].lock = 0; 371 GDTH_UNLOCK_HA(ha, flags); 372 gdth_start_timeout( hanum, ha->bus_cnt, j ); 373 gdth_next( hanum ); 374 } 375 } 376 piord->size = sizeof(gdth_iord_str); 377 piord->status = S_OK; 378 break; 379 380 case GDTIOCTL_LOCKCHN: 381 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 382 return(-EBUSY); 383 i = piowr->iu.lockchn.channel; 384 if (i < ha->bus_cnt) { 385 if (piowr->iu.lockchn.lock) { 386 GDTH_LOCK_HA(ha, flags); 387 ha->raw[i].lock = 1; 388 GDTH_UNLOCK_HA(ha, flags); 389 for (j = 0; j < ha->tid_cnt; ++j) { 390 gdth_wait_completion( hanum, i, j ); 391 gdth_stop_timeout( hanum, i, j ); 392 } 393 } else { 394 GDTH_LOCK_HA(ha, flags); 395 ha->raw[i].lock = 0; 396 GDTH_UNLOCK_HA(ha, flags); 397 for (j = 0; j < ha->tid_cnt; ++j) { 398 gdth_start_timeout( hanum, i, j ); 399 gdth_next( hanum ); 400 } 401 } 402 } 403 piord = (gdth_iord_str *)ha->pscratch; 404 piord->size = sizeof(gdth_iord_str); 405 piord->status = S_OK; 406 break; 407 408 case GDTIOCTL_EVENT: 409 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 410 return(-EBUSY); 411 piord = (gdth_iord_str *)ha->pscratch; 412 if (piowr->iu.event.erase == 0xff) { 413 pevt = (gdth_evt_str *)piowr->iu.event.evt; 414 if (pevt->event_source == ES_TEST) 415 pevt->event_data.size = sizeof(pevt->event_data.eu.test); 416 else if (pevt->event_source == ES_DRIVER) 417 pevt->event_data.size = sizeof(pevt->event_data.eu.driver); 418 else if (pevt->event_source == ES_SYNC) 419 pevt->event_data.size = sizeof(pevt->event_data.eu.sync); 420 else { 421 pevt->event_data.size = sizeof(pevt->event_data.eu.async); 422 gdth_log_event(&pevt->event_data, NULL); 423 } 424 GDTH_LOCK_HA(ha, flags); 425 gdth_store_event(ha, pevt->event_source, pevt->event_idx, 426 &pevt->event_data); 427 GDTH_UNLOCK_HA(ha, flags); 428 } else if (piowr->iu.event.erase == 0xfe) { 429 gdth_clear_events(); 430 } else if (piowr->iu.event.erase == 0) { 431 piord->iu.event.handle = 432 gdth_read_event(ha,piowr->iu.event.handle, 433 (gdth_evt_str *)piord->iu.event.evt); 434 } else { 435 piord->iu.event.handle = piowr->iu.event.handle; 436 gdth_readapp_event(ha, (unchar)piowr->iu.event.erase, 437 (gdth_evt_str *)piord->iu.event.evt); 438 } 439 piord->size = sizeof(gdth_iord_str); 440 piord->status = S_OK; 441 break; 442 443 case GDTIOCTL_SCSI: 444 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 445 return(-EBUSY); 446 piord = (gdth_iord_str *)ha->pscratch; 447 piord->size = sizeof(gdth_iord_str); 448 memcpy(cmnd, piowr->iu.scsi.cmd, 12); 449#if LINUX_VERSION_CODE >= 0x020322 450 scp->target = piowr->iu.scsi.target; 451 scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus; 452 scp->cmd_len = piowr->iu.scsi.cmd_len; 453 gdth_do_cmd(scp, pcmd, cmnd, piowr->timeout); 454 piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; 455#else 456 scp.target = piowr->iu.scsi.target; 457 scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus; 458 scp.cmd_len = piowr->iu.scsi.cmd_len; 459 gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout); 460 piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; 461#endif 462 break; 463 464 case GDTIOCTL_RESET_BUS: 465 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 466 return(-EBUSY); 467 piord = (gdth_iord_str *)ha->pscratch; 468 piord->size = sizeof(gdth_iord_str); 469#if LINUX_VERSION_CODE >= 0x020322 470 scp->channel = virt_ctr ? 0 : piowr->iu.scsi.bus; 471 piord->status = (ulong32)gdth_eh_bus_reset( scp ); 472 if (piord->status == SUCCESS) 473 piord->status = S_OK; 474 else 475 piord->status = S_GENERR; 476#elif LINUX_VERSION_CODE >= 0x02015F 477 scp.channel = virt_ctr ? 0 : piowr->iu.scsi.bus; 478 piord->status = (ulong32)gdth_eh_bus_reset( &scp ); 479 if (piord->status == SUCCESS) 480 piord->status = S_OK; 481 else 482 piord->status = S_GENERR; 483#else 484 piord->status = S_OK; 485#endif 486 break; 487 488 case GDTIOCTL_HDRLIST: 489 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 490 return(-EBUSY); 491 piord = (gdth_iord_str *)ha->pscratch; 492 piord->size = sizeof(gdth_iord_str); 493 piord->status = S_OK; 494 for (i = 0; i < MAX_HDRIVES; ++i) { 495 if (ha->hdr[i].present) { 496 piord->iu.hdr_list[i].bus = ha->virt_bus; 497 piord->iu.hdr_list[i].target = i; 498 piord->iu.hdr_list[i].lun = 0; 499 piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type; 500 if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { 501 gdtcmd.Service = CACHESERVICE; 502 gdtcmd.OpCode = GDT_CLUST_INFO; 503 gdtcmd.u.cache.DeviceNo = i; 504#if LINUX_VERSION_CODE >= 0x020322 505 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 506 if (scp->SCp.Status == S_OK) 507 piord->iu.hdr_list[i].cluster_type = 508 (unchar)scp->SCp.Message; 509#else 510 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 511 if (scp.SCp.Status == S_OK) 512 piord->iu.hdr_list[i].cluster_type = 513 (unchar)scp.SCp.Message; 514#endif 515 } 516 } else { 517 piord->iu.hdr_list[i].bus = 0xff; 518 } 519 } 520 break; 521 522 case GDTIOCTL_RESCAN: 523 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 524 return(-EBUSY); 525 piord = (gdth_iord_str *)ha->pscratch; 526 piord->size = sizeof(gdth_iord_str); 527 piord->status = S_OK; 528 if (piowr->iu.rescan.flag == 0) { 529 /* old method: scan all host drives 530 re-initialize cache service to get host drive count 531 */ 532 gdtcmd.Service = CACHESERVICE; 533 gdtcmd.OpCode = GDT_INIT; 534 gdtcmd.u.cache.DeviceNo = LINUX_OS; 535#if LINUX_VERSION_CODE >= 0x020322 536 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 537 status = (ushort)scp->SCp.Status; 538 info = (ulong32)scp->SCp.Message; 539#else 540 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 541 status = (ushort)scp.SCp.Status; 542 info = (ulong32)scp.SCp.Message; 543#endif 544 if (status != S_OK) 545 break; 546 k = 0; 547 hdr_cnt = (ushort)info; 548 } else { 549 k = piowr->iu.rescan.hdr_no; 550 hdr_cnt = k + 1; 551 } 552 if (hdr_cnt > MAX_HDRIVES) 553 hdr_cnt = MAX_HDRIVES; 554 /* scanning for host drives */ 555 for (; k < hdr_cnt; ++k) { 556 /* info about host drive */ 557 gdtcmd.Service = CACHESERVICE; 558 gdtcmd.OpCode = GDT_INFO; 559 gdtcmd.u.cache.DeviceNo = k; 560#if LINUX_VERSION_CODE >= 0x020322 561 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 562 status = (ushort)scp->SCp.Status; 563 info = (ulong32)scp->SCp.Message; 564#else 565 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 566 status = (ushort)scp.SCp.Status; 567 info = (ulong32)scp.SCp.Message; 568#endif 569 GDTH_LOCK_HA(ha, flags); 570 piord->iu.hdr_list[k].bus = ha->virt_bus; 571 piord->iu.hdr_list[k].target = k; 572 piord->iu.hdr_list[k].lun = 0; 573 if (status != S_OK) { 574 ha->hdr[k].present = FALSE; 575 } else { 576 ha->hdr[k].present = TRUE; 577 ha->hdr[k].size = info; 578 /* evaluate mapping (sectors per head, heads per cylinder) */ 579 ha->hdr[k].size &= ~SECS32; 580 gdth_eval_mapping(ha->hdr[k].size,&drv_cyls,&drv_hds,&drv_secs); 581 ha->hdr[k].heads = (unchar)drv_hds; 582 ha->hdr[k].secs = (unchar)drv_secs; 583 /* round size */ 584 ha->hdr[k].size = drv_cyls * drv_hds * drv_secs; 585 } 586 GDTH_UNLOCK_HA(ha, flags); 587 if (status != S_OK) 588 continue; /* next host drive */ 589 590 /* devtype, cluster info, R/W attributes */ 591 gdtcmd.Service = CACHESERVICE; 592 gdtcmd.OpCode = GDT_DEVTYPE; 593 gdtcmd.u.cache.DeviceNo = k; 594#if LINUX_VERSION_CODE >= 0x020322 595 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 596 status = (ushort)scp->SCp.Status; 597 info = (ulong32)scp->SCp.Message; 598#else 599 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 600 status = (ushort)scp.SCp.Status; 601 info = (ulong32)scp.SCp.Message; 602#endif 603 GDTH_LOCK_HA(ha, flags); 604 ha->hdr[k].devtype = 0; 605 if (status == S_OK) 606 ha->hdr[k].devtype = (ushort)info; 607 GDTH_UNLOCK_HA(ha, flags); 608 609 gdtcmd.Service = CACHESERVICE; 610 gdtcmd.OpCode = GDT_CLUST_INFO; 611 gdtcmd.u.cache.DeviceNo = k; 612#if LINUX_VERSION_CODE >= 0x020322 613 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 614 status = (ushort)scp->SCp.Status; 615 info = (ulong32)scp->SCp.Message; 616#else 617 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 618 status = (ushort)scp.SCp.Status; 619 info = (ulong32)scp.SCp.Message; 620#endif 621 GDTH_LOCK_HA(ha, flags); 622 ha->hdr[k].cluster_type = 0; 623 if (status == S_OK && !shared_access) 624 ha->hdr[k].cluster_type = (ushort)info; 625 GDTH_UNLOCK_HA(ha, flags); 626 piord->iu.hdr_list[k].cluster_type = ha->hdr[k].cluster_type; 627 628 gdtcmd.Service = CACHESERVICE; 629 gdtcmd.OpCode = GDT_RW_ATTRIBS; 630 gdtcmd.u.cache.DeviceNo = k; 631#if LINUX_VERSION_CODE >= 0x020322 632 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 633 status = (ushort)scp->SCp.Status; 634 info = (ulong32)scp->SCp.Message; 635#else 636 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 637 status = (ushort)scp.SCp.Status; 638 info = (ulong32)scp.SCp.Message; 639#endif 640 GDTH_LOCK_HA(ha, flags); 641 ha->hdr[k].rw_attribs = 0; 642 if (status == S_OK) 643 ha->hdr[k].rw_attribs = (ushort)info; 644 GDTH_UNLOCK_HA(ha, flags); 645 } 646 break; 647 648 case GDTIOCTL_RESET_DRV: 649 if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str), TRUE )) 650 return(-EBUSY); 651 piord = (gdth_iord_str *)ha->pscratch; 652 piord->size = sizeof(gdth_iord_str); 653 piord->status = S_OK; 654 i = piowr->iu.scsi.target; 655 if (ha->hdr[i].present) { 656 gdtcmd.Service = CACHESERVICE; 657 gdtcmd.OpCode = GDT_CLUST_RESET; 658 gdtcmd.u.cache.DeviceNo = i; 659#if LINUX_VERSION_CODE >= 0x020322 660 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 661 piord->status = (scp->SCp.Message<<16)|scp->SCp.Status; 662#else 663 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 664 piord->status = (scp.SCp.Message<<16)|scp.SCp.Status; 665#endif 666 } 667 break; 668 669 default: 670 return(-EINVAL); 671 } 672 return length; 673} 674 675static int gdth_get_info(char *buffer,char **start,off_t offset, 676 int length,int vh,int hanum,int busnum) 677{ 678 int size = 0,len = 0; 679 off_t begin = 0,pos = 0; 680 gdth_ha_str *ha; 681 gdth_iord_str *piord; 682 int id, i, j, k, sec, flag; 683 int no_mdrv = 0, drv_no, is_mirr; 684 ulong32 cnt; 685 686 gdth_cmd_str gdtcmd; 687 gdth_evt_str estr; 688#if LINUX_VERSION_CODE >= 0x020322 689 Scsi_Cmnd *scp; 690 Scsi_Device *sdev; 691#else 692 Scsi_Cmnd scp; 693 Scsi_Device sdev; 694#endif 695 char hrec[161]; 696 struct timeval tv; 697 698 char *buf; 699 gdth_dskstat_str *pds; 700 gdth_diskinfo_str *pdi; 701 gdth_arrayinf_str *pai; 702 gdth_defcnt_str *pdef; 703 gdth_cdrinfo_str *pcdi; 704 gdth_hget_str *phg; 705 706 char cmnd[MAX_COMMAND_SIZE]; 707 memset(cmnd, 0xff, 12); 708 memset(&gdtcmd, 0, sizeof(gdth_cmd_str)); 709 710 TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum)); 711 ha = HADATA(gdth_ctr_tab[hanum]); 712 713#if LINUX_VERSION_CODE >= 0x020322 714 sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]); 715 scp = scsi_allocate_device(sdev, 1, FALSE); 716 if (!scp) 717 return -ENOMEM; 718 scp->cmd_len = 12; 719 scp->use_sg = 0; 720#else 721 memset(&sdev,0,sizeof(Scsi_Device)); 722 memset(&scp, 0,sizeof(Scsi_Cmnd)); 723 sdev.host = scp.host = gdth_ctr_vtab[vh]; 724 sdev.id = scp.target = sdev.host->this_id; 725 scp.device = &sdev; 726#endif 727 728 /* ioctl from tool? */ 729 if (!gdth_ioctl_check_bin(hanum, (ushort)length)) { 730 /* request is i.e. "cat /proc/scsi/gdth/0" */ 731 /* format: %-15s\t%-10s\t%-15s\t%s */ 732 /* driver parameters */ 733 size = sprintf(buffer+len,"Driver Parameters:\n"); 734 len += size; pos = begin + len; 735 if (reserve_list[0] == 0xff) 736 strcpy(hrec, "--"); 737 else { 738 sprintf(hrec, "%d", reserve_list[0]); 739 for (i = 1; i < MAX_RES_ARGS; i++) { 740 if (reserve_list[i] == 0xff) 741 break; 742 sprintf(hrec,"%s,%d", hrec, reserve_list[i]); 743 } 744 } 745 size = sprintf(buffer+len, 746 " reserve_mode: \t%d \treserve_list: \t%s\n", 747 reserve_mode, hrec); 748 len += size; pos = begin + len; 749 size = sprintf(buffer+len, 750 " max_ids: \t%-3d \thdr_channel: \t%d\n", 751 max_ids, hdr_channel); 752 len += size; pos = begin + len; 753 754 /* controller information */ 755 size = sprintf(buffer+len,"\nDisk Array Controller Information:\n"); 756 len += size; pos = begin + len; 757 if (virt_ctr) 758 sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum); 759 else 760 strcpy(hrec, ha->binfo.type_string); 761 size = sprintf(buffer+len, 762 " Number: \t%d \tName: \t%s\n", 763 hanum, hrec); 764 len += size; pos = begin + len; 765 766 if (ha->more_proc) 767 sprintf(hrec, "%d.%02d.%02d-%c%03X", 768 (unchar)(ha->binfo.upd_fw_ver>>24), 769 (unchar)(ha->binfo.upd_fw_ver>>16), 770 (unchar)(ha->binfo.upd_fw_ver), 771 ha->bfeat.raid ? 'R':'N', 772 ha->binfo.upd_revision); 773 else 774 sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8), 775 (unchar)(ha->cpar.version)); 776 777 size = sprintf(buffer+len, 778 " Driver Ver.: \t%-10s\tFirmware Ver.: \t%s\n", 779 GDTH_VERSION_STR, hrec); 780 len += size; pos = begin + len; 781 782 if (pos < offset) { 783 len = 0; 784 begin = pos; 785 } 786 if (pos > offset + length) 787 goto stop_output; 788 789 if (ha->more_proc) { 790 /* more information: 1. about controller */ 791 size = sprintf(buffer+len, 792 " Serial No.: \t0x%8X\tCache RAM size:\t%d KB\n", 793 ha->binfo.ser_no, ha->binfo.memsize / 1024); 794 len += size; pos = begin + len; 795 796 /* 2. about physical devices */ 797 size = sprintf(buffer+len,"\nPhysical Devices:"); 798 len += size; pos = begin + len; 799 flag = FALSE; 800 801 buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE); 802 if (!buf) 803 goto stop_output; 804 for (i = 0; i < ha->bus_cnt; ++i) { 805 /* 2.a statistics (and retries/reassigns) */ 806 TRACE2(("pdr_statistics() chn %d\n",i)); 807 pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4); 808 gdtcmd.Service = CACHESERVICE; 809 gdtcmd.OpCode = GDT_IOCTL; 810 gdtcmd.u.ioctl.p_param = virt_to_bus(pds); 811 gdtcmd.u.ioctl.param_size = 3*GDTH_SCRATCH/4; 812 gdtcmd.u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN; 813 gdtcmd.u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL; 814 pds->bid = ha->raw[i].local_no; 815 pds->first = 0; 816 pds->entries = ha->raw[i].pdev_cnt; 817 cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) / 818 sizeof(pds->list[0]); 819 if (pds->entries > cnt) 820 pds->entries = cnt; 821#if LINUX_VERSION_CODE >= 0x020322 822 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 823 if (scp->SCp.Status != S_OK) 824#else 825 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 826 if (scp.SCp.Status != S_OK) 827#endif 828 { 829 pds->count = 0; 830 } 831 832 /* other IOCTLs must fit into area GDTH_SCRATCH/4 */ 833 for (j = 0; j < ha->raw[i].pdev_cnt; ++j) { 834 /* 2.b drive info */ 835 TRACE2(("scsi_drv_info() chn %d dev %d\n", 836 i, ha->raw[i].id_list[j])); 837 pdi = (gdth_diskinfo_str *)buf; 838 gdtcmd.Service = CACHESERVICE; 839 gdtcmd.OpCode = GDT_IOCTL; 840 gdtcmd.u.ioctl.p_param = virt_to_bus(pdi); 841 gdtcmd.u.ioctl.param_size = sizeof(gdth_diskinfo_str); 842 gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN; 843 gdtcmd.u.ioctl.channel = 844 ha->raw[i].address | ha->raw[i].id_list[j]; 845#if LINUX_VERSION_CODE >= 0x020322 846 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 847 if (scp->SCp.Status == S_OK) 848#else 849 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 850 if (scp.SCp.Status == S_OK) 851#endif 852 { 853 strncpy(hrec,pdi->vendor,8); 854 strncpy(hrec+8,pdi->product,16); 855 strncpy(hrec+24,pdi->revision,4); 856 hrec[28] = 0; 857 size = sprintf(buffer+len, 858 "\n Chn/ID/LUN: \t%c/%02d/%d \tName: \t%s\n", 859 'A'+i,pdi->target_id,pdi->lun,hrec); 860 len += size; pos = begin + len; 861 flag = TRUE; 862 pdi->no_ldrive &= 0xffff; 863 if (pdi->no_ldrive == 0xffff) 864 strcpy(hrec,"--"); 865 else 866 sprintf(hrec,"%d",pdi->no_ldrive); 867 size = sprintf(buffer+len, 868 " Capacity [MB]:\t%-6d \tTo Log. Drive: \t%s\n", 869 pdi->blkcnt/(1024*1024/pdi->blksize), 870 hrec); 871 len += size; pos = begin + len; 872 } else { 873 pdi->devtype = 0xff; 874 } 875 876 if (pdi->devtype == 0) { 877 /* search retries/reassigns */ 878 for (k = 0; k < pds->count; ++k) { 879 if (pds->list[k].tid == pdi->target_id && 880 pds->list[k].lun == pdi->lun) { 881 size = sprintf(buffer+len, 882 " Retries: \t%-6d \tReassigns: \t%d\n", 883 pds->list[k].retries, 884 pds->list[k].reassigns); 885 len += size; pos = begin + len; 886 break; 887 } 888 } 889 /* 2.c grown defects */ 890 TRACE2(("scsi_drv_defcnt() chn %d dev %d\n", 891 i, ha->raw[i].id_list[j])); 892 pdef = (gdth_defcnt_str *)buf; 893 gdtcmd.Service = CACHESERVICE; 894 gdtcmd.OpCode = GDT_IOCTL; 895 gdtcmd.u.ioctl.p_param = virt_to_bus(pdef); 896 gdtcmd.u.ioctl.param_size = sizeof(gdth_defcnt_str); 897 gdtcmd.u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN; 898 gdtcmd.u.ioctl.channel = 899 ha->raw[i].address | ha->raw[i].id_list[j]; 900 pdef->sddc_type = 0x08; 901#if LINUX_VERSION_CODE >= 0x020322 902 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 903 if (scp->SCp.Status == S_OK) 904#else 905 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 906 if (scp.SCp.Status == S_OK) 907#endif 908 { 909 size = sprintf(buffer+len, 910 " Grown Defects:\t%d\n", 911 pdef->sddc_cnt); 912 len += size; pos = begin + len; 913 } 914 } 915 if (pos < offset) { 916 len = 0; 917 begin = pos; 918 } 919 if (pos > offset + length) 920 goto stop_output; 921 } 922 } 923 gdth_ioctl_free(hanum, buf); 924 925 if (!flag) { 926 size = sprintf(buffer+len, "\n --\n"); 927 len += size; pos = begin + len; 928 } 929 930 /* 3. about logical drives */ 931 size = sprintf(buffer+len,"\nLogical Drives:"); 932 len += size; pos = begin + len; 933 flag = FALSE; 934 935 buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE); 936 if (!buf) 937 goto stop_output; 938 for (i = 0; i < MAX_LDRIVES; ++i) { 939 if (!ha->hdr[i].is_logdrv) 940 continue; 941 drv_no = i; 942 j = k = 0; 943 is_mirr = FALSE; 944 do { 945 /* 3.a log. drive info */ 946 TRACE2(("cache_drv_info() drive no %d\n",drv_no)); 947 pcdi = (gdth_cdrinfo_str *)buf; 948 gdtcmd.Service = CACHESERVICE; 949 gdtcmd.OpCode = GDT_IOCTL; 950 gdtcmd.u.ioctl.p_param = virt_to_bus(pcdi); 951 gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str); 952 gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO; 953 gdtcmd.u.ioctl.channel = drv_no; 954#if LINUX_VERSION_CODE >= 0x020322 955 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 956 if (scp->SCp.Status != S_OK) 957#else 958 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 959 if (scp.SCp.Status != S_OK) 960#endif 961 { 962 break; 963 } 964 pcdi->ld_dtype >>= 16; 965 j++; 966 if (pcdi->ld_dtype > 2) { 967 strcpy(hrec, "missing"); 968 } else if (pcdi->ld_error & 1) { 969 strcpy(hrec, "fault"); 970 } else if (pcdi->ld_error & 2) { 971 strcpy(hrec, "invalid"); 972 k++; j--; 973 } else { 974 strcpy(hrec, "ok"); 975 } 976 977 if (drv_no == i) { 978 size = sprintf(buffer+len, 979 "\n Number: \t%-2d \tStatus: \t%s\n", 980 drv_no, hrec); 981 len += size; pos = begin + len; 982 flag = TRUE; 983 no_mdrv = pcdi->cd_ldcnt; 984 if (no_mdrv > 1 || pcdi->ld_slave != -1) { 985 is_mirr = TRUE; 986 strcpy(hrec, "RAID-1"); 987 } else if (pcdi->ld_dtype == 0) { 988 strcpy(hrec, "Disk"); 989 } else if (pcdi->ld_dtype == 1) { 990 strcpy(hrec, "RAID-0"); 991 } else if (pcdi->ld_dtype == 2) { 992 strcpy(hrec, "Chain"); 993 } else { 994 strcpy(hrec, "???"); 995 } 996 size = sprintf(buffer+len, 997 " Capacity [MB]:\t%-6d \tType: \t%s\n", 998 pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize), 999 hrec); 1000 len += size; pos = begin + len; 1001 } else { 1002 size = sprintf(buffer+len, 1003 " Slave Number: \t%-2d \tStatus: \t%s\n", 1004 drv_no & 0x7fff, hrec); 1005 len += size; pos = begin + len; 1006 } 1007 drv_no = pcdi->ld_slave; 1008 if (pos < offset) { 1009 len = 0; 1010 begin = pos; 1011 } 1012 if (pos > offset + length) 1013 goto stop_output; 1014 } while (drv_no != -1); 1015 1016 if (is_mirr) { 1017 size = sprintf(buffer+len, 1018 " Missing Drv.: \t%-2d \tInvalid Drv.: \t%d\n", 1019 no_mdrv - j - k, k); 1020 len += size; pos = begin + len; 1021 } 1022 1023 if (!ha->hdr[i].is_arraydrv) 1024 strcpy(hrec, "--"); 1025 else 1026 sprintf(hrec, "%d", ha->hdr[i].master_no); 1027 size = sprintf(buffer+len, 1028 " To Array Drv.:\t%s\n", hrec); 1029 len += size; pos = begin + len; 1030 if (pos < offset) { 1031 len = 0; 1032 begin = pos; 1033 } 1034 if (pos > offset + length) 1035 goto stop_output; 1036 } 1037 gdth_ioctl_free(hanum, buf); 1038 1039 if (!flag) { 1040 size = sprintf(buffer+len, "\n --\n"); 1041 len += size; pos = begin + len; 1042 } 1043 1044 /* 4. about array drives */ 1045 size = sprintf(buffer+len,"\nArray Drives:"); 1046 len += size; pos = begin + len; 1047 flag = FALSE; 1048 1049 buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE); 1050 if (!buf) 1051 goto stop_output; 1052 for (i = 0; i < MAX_LDRIVES; ++i) { 1053 if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master)) 1054 continue; 1055 /* 4.a array drive info */ 1056 TRACE2(("array_info() drive no %d\n",i)); 1057 pai = (gdth_arrayinf_str *)buf; 1058 gdtcmd.Service = CACHESERVICE; 1059 gdtcmd.OpCode = GDT_IOCTL; 1060 gdtcmd.u.ioctl.p_param = virt_to_bus(pai); 1061 gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str); 1062 gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN; 1063 gdtcmd.u.ioctl.channel = i; 1064#if LINUX_VERSION_CODE >= 0x020322 1065 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 1066 if (scp->SCp.Status == S_OK) 1067#else 1068 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 1069 if (scp.SCp.Status == S_OK) 1070#endif 1071 { 1072 if (pai->ai_state == 0) 1073 strcpy(hrec, "idle"); 1074 else if (pai->ai_state == 2) 1075 strcpy(hrec, "build"); 1076 else if (pai->ai_state == 4) 1077 strcpy(hrec, "ready"); 1078 else if (pai->ai_state == 6) 1079 strcpy(hrec, "fail"); 1080 else if (pai->ai_state == 8 || pai->ai_state == 10) 1081 strcpy(hrec, "rebuild"); 1082 else 1083 strcpy(hrec, "error"); 1084 if (pai->ai_ext_state & 0x10) 1085 strcat(hrec, "/expand"); 1086 else if (pai->ai_ext_state & 0x1) 1087 strcat(hrec, "/patch"); 1088 size = sprintf(buffer+len, 1089 "\n Number: \t%-2d \tStatus: \t%s\n", 1090 i,hrec); 1091 len += size; pos = begin + len; 1092 flag = TRUE; 1093 1094 if (pai->ai_type == 0) 1095 strcpy(hrec, "RAID-0"); 1096 else if (pai->ai_type == 4) 1097 strcpy(hrec, "RAID-4"); 1098 else if (pai->ai_type == 5) 1099 strcpy(hrec, "RAID-5"); 1100 else 1101 strcpy(hrec, "RAID-10"); 1102 size = sprintf(buffer+len, 1103 " Capacity [MB]:\t%-6d \tType: \t%s\n", 1104 pai->ai_size/(1024*1024/pai->ai_secsize), 1105 hrec); 1106 len += size; pos = begin + len; 1107 if (pos < offset) { 1108 len = 0; 1109 begin = pos; 1110 } 1111 if (pos > offset + length) 1112 goto stop_output; 1113 } 1114 } 1115 gdth_ioctl_free(hanum, buf); 1116 1117 if (!flag) { 1118 size = sprintf(buffer+len, "\n --\n"); 1119 len += size; pos = begin + len; 1120 } 1121 1122 /* 5. about host drives */ 1123 size = sprintf(buffer+len,"\nHost Drives:"); 1124 len += size; pos = begin + len; 1125 flag = FALSE; 1126 1127 buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE); 1128 if (!buf) 1129 goto stop_output; 1130 for (i = 0; i < MAX_LDRIVES; ++i) { 1131 if (!ha->hdr[i].is_logdrv || 1132 (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master)) 1133 continue; 1134 /* 5.a get host drive list */ 1135 TRACE2(("host_get() drv_no %d\n",i)); 1136 phg = (gdth_hget_str *)buf; 1137 gdtcmd.Service = CACHESERVICE; 1138 gdtcmd.OpCode = GDT_IOCTL; 1139 gdtcmd.u.ioctl.p_param = virt_to_bus(phg); 1140 gdtcmd.u.ioctl.param_size = sizeof(gdth_hget_str); 1141 gdtcmd.u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN; 1142 gdtcmd.u.ioctl.channel = i; 1143 phg->entries = MAX_HDRIVES; 1144 phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 1145#if LINUX_VERSION_CODE >= 0x020322 1146 gdth_do_cmd(scp, &gdtcmd, cmnd, 30); 1147 if (scp->SCp.Status != S_OK) 1148#else 1149 gdth_do_cmd(&scp, &gdtcmd, cmnd, 30); 1150 if (scp.SCp.Status != S_OK) 1151#endif 1152 { 1153 ha->hdr[i].ldr_no = i; 1154 ha->hdr[i].rw_attribs = 0; 1155 ha->hdr[i].start_sec = 0; 1156 } else { 1157 for (j = 0; j < phg->entries; ++j) { 1158 k = phg->entry[j].host_drive; 1159 if (k >= MAX_LDRIVES) 1160 continue; 1161 ha->hdr[k].ldr_no = phg->entry[j].log_drive; 1162 ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs; 1163 ha->hdr[k].start_sec = phg->entry[j].start_sec; 1164 } 1165 } 1166 } 1167 gdth_ioctl_free(hanum, buf); 1168 1169 for (i = 0; i < MAX_HDRIVES; ++i) { 1170 if (!(ha->hdr[i].present)) 1171 continue; 1172 1173 size = sprintf(buffer+len, 1174 "\n Number: \t%-2d \tArr/Log. Drive:\t%d\n", 1175 i, ha->hdr[i].ldr_no); 1176 len += size; pos = begin + len; 1177 flag = TRUE; 1178 1179 size = sprintf(buffer+len, 1180 " Capacity [MB]:\t%-6d \tStart Sector: \t%d\n", 1181 ha->hdr[i].size/2048, ha->hdr[i].start_sec); 1182 len += size; pos = begin + len; 1183 if (pos < offset) { 1184 len = 0; 1185 begin = pos; 1186 } 1187 if (pos > offset + length) 1188 goto stop_output; 1189 } 1190 1191 if (!flag) { 1192 size = sprintf(buffer+len, "\n --\n"); 1193 len += size; pos = begin + len; 1194 } 1195 } 1196 1197 /* controller events */ 1198 size = sprintf(buffer+len,"\nController Events:\n"); 1199 len += size; pos = begin + len; 1200 1201 for (id = -1;;) { 1202 id = gdth_read_event(ha, id, &estr); 1203 if (estr.event_source == 0) 1204 break; 1205 if (estr.event_data.eu.driver.ionode == hanum && 1206 estr.event_source == ES_ASYNC) { 1207 gdth_log_event(&estr.event_data, hrec); 1208 do_gettimeofday(&tv); 1209 sec = (int)(tv.tv_sec - estr.first_stamp); 1210 if (sec < 0) sec = 0; 1211 size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n", 1212 sec/3600, sec%3600/60, sec%60, hrec); 1213 len += size; pos = begin + len; 1214 if (pos < offset) { 1215 len = 0; 1216 begin = pos; 1217 } 1218 if (pos > offset + length) 1219 goto stop_output; 1220 } 1221 if (id == -1) 1222 break; 1223 } 1224 } else { 1225 /* request from tool (GDTMON,..) */ 1226 piord = (gdth_iord_str *)ha->pscratch; 1227 if (piord == NULL) 1228 goto stop_output; 1229 length = piord->size; 1230 memcpy(buffer+len, (char *)piord, length); 1231 gdth_ioctl_free(hanum, ha->pscratch); 1232 len = length; 1233 } 1234 1235stop_output: 1236#if LINUX_VERSION_CODE >= 0x020322 1237 scsi_release_command(scp); 1238 scsi_free_host_dev(sdev); 1239#endif 1240 *start = buffer +(offset-begin); 1241 len -= (offset-begin); 1242 if (len > length) 1243 len = length; 1244 TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n", 1245 len,(int)pos,(int)begin,(int)offset,length,size)); 1246 return(len); 1247} 1248 1249static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 1250 char *cmnd, int timeout) 1251{ 1252 unsigned bufflen; 1253#if LINUX_VERSION_CODE >= 0x020407 1254 DECLARE_COMPLETION(wait); 1255#elif LINUX_VERSION_CODE >= 0x020322 1256 DECLARE_MUTEX_LOCKED(sem); 1257#else 1258 struct semaphore sem = MUTEX_LOCKED; 1259#endif 1260 1261 TRACE2(("gdth_do_cmd()\n")); 1262 if (gdtcmd != NULL) { 1263 scp->SCp.this_residual = IOCTL_PRI; 1264 bufflen = sizeof(gdth_cmd_str); 1265 } else { 1266 scp->SCp.this_residual = DEFAULT_PRI; 1267 bufflen = 0; 1268 } 1269 scp->request.rq_status = RQ_SCSI_BUSY; 1270#if LINUX_VERSION_CODE >= 0x020407 1271 scp->request.waiting = &wait; 1272 scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); 1273 wait_for_completion(&wait); 1274#else 1275 scp->request.sem = &sem; 1276#if LINUX_VERSION_CODE >= 0x020322 1277 scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); 1278#else 1279 GDTH_LOCK_SCSI_DOCMD(); 1280 scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1); 1281 GDTH_UNLOCK_SCSI_DOCMD(); 1282#endif 1283 down(&sem); 1284#endif 1285} 1286 1287void gdth_scsi_done(Scsi_Cmnd *scp) 1288{ 1289 TRACE2(("gdth_scsi_done()\n")); 1290 1291 scp->request.rq_status = RQ_SCSI_DONE; 1292 1293#if LINUX_VERSION_CODE >= 0x020407 1294 if (scp->request.waiting != NULL) 1295 complete(scp->request.waiting); 1296#else 1297 if (scp->request.sem != NULL) 1298 up(scp->request.sem); 1299#endif 1300} 1301 1302static char *gdth_ioctl_alloc(int hanum, ushort size, int scratch) 1303{ 1304 gdth_ha_str *ha; 1305 ulong flags; 1306 char *ret_val; 1307 1308 if (size == 0 || size > GDTH_SCRATCH) 1309 return FALSE; 1310 1311 ha = HADATA(gdth_ctr_tab[hanum]); 1312 GDTH_LOCK_HA(ha, flags); 1313 1314 if (scratch) { 1315 if (!ha->scratch_busy) { 1316 ha->scratch_busy = TRUE; 1317 ret_val = ha->pscratch; 1318 } else 1319 ret_val = NULL; 1320 } else { 1321#if LINUX_VERSION_CODE >= 0x020322 1322 ret_val = (void *) __get_free_pages(GFP_ATOMIC | GFP_DMA, 1323 GDTH_SCRATCH_ORD); 1324#else 1325 ret_val = scsi_init_malloc(GDTH_SCRATCH, GFP_ATOMIC | GFP_DMA); 1326#endif 1327 } 1328 1329 GDTH_UNLOCK_HA(ha, flags); 1330 return ret_val; 1331} 1332 1333static void gdth_ioctl_free(int hanum, char *buf) 1334{ 1335 gdth_ha_str *ha; 1336 ulong flags; 1337 1338 ha = HADATA(gdth_ctr_tab[hanum]); 1339 GDTH_LOCK_HA(ha, flags); 1340 1341 if (buf == ha->pscratch) { 1342 ha->scratch_busy = FALSE; 1343 } else { 1344#if LINUX_VERSION_CODE >= 0x020322 1345 free_pages((unsigned long)buf, GDTH_SCRATCH_ORD); 1346#else 1347 scsi_init_free((void *)buf, GDTH_SCRATCH); 1348#endif 1349 } 1350 1351 GDTH_UNLOCK_HA(ha, flags); 1352} 1353 1354static int gdth_ioctl_check_bin(int hanum, ushort size) 1355{ 1356 gdth_ha_str *ha; 1357 ulong flags; 1358 int ret_val; 1359 1360 ha = HADATA(gdth_ctr_tab[hanum]); 1361 GDTH_LOCK_HA(ha, flags); 1362 1363 ret_val = FALSE; 1364 if (ha->scratch_busy) { 1365 if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size) 1366 ret_val = TRUE; 1367 } 1368 GDTH_UNLOCK_HA(ha, flags); 1369 return ret_val; 1370} 1371 1372 1373static void gdth_wait_completion(int hanum, int busnum, int id) 1374{ 1375 gdth_ha_str *ha; 1376 ulong flags; 1377 int i; 1378 Scsi_Cmnd *scp; 1379 unchar b; 1380 1381 ha = HADATA(gdth_ctr_tab[hanum]); 1382 GDTH_LOCK_HA(ha, flags); 1383 1384 for (i = 0; i < GDTH_MAXCMDS; ++i) { 1385 scp = ha->cmd_tab[i].cmnd; 1386 b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; 1387 if (!SPECIAL_SCP(scp) && scp->target == (unchar)id && 1388 b == (unchar)busnum) { 1389 scp->SCp.have_data_in = 0; 1390 GDTH_UNLOCK_HA(ha, flags); 1391 while (!scp->SCp.have_data_in) 1392 barrier(); 1393 GDTH_LOCK_SCSI_DONE(flags); 1394 scp->scsi_done(scp); 1395 GDTH_UNLOCK_SCSI_DONE(flags); 1396 GDTH_LOCK_HA(ha, flags); 1397 } 1398 } 1399 GDTH_UNLOCK_HA(ha, flags); 1400} 1401 1402static void gdth_stop_timeout(int hanum, int busnum, int id) 1403{ 1404 gdth_ha_str *ha; 1405 ulong flags; 1406 Scsi_Cmnd *scp; 1407 unchar b; 1408 1409 ha = HADATA(gdth_ctr_tab[hanum]); 1410 GDTH_LOCK_HA(ha, flags); 1411 1412 for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { 1413 b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; 1414 if (scp->target == (unchar)id && b == (unchar)busnum) { 1415 TRACE2(("gdth_stop_timeout(): update_timeout()\n")); 1416 scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0); 1417 } 1418 } 1419 GDTH_UNLOCK_HA(ha, flags); 1420} 1421 1422static void gdth_start_timeout(int hanum, int busnum, int id) 1423{ 1424 gdth_ha_str *ha; 1425 ulong flags; 1426 Scsi_Cmnd *scp; 1427 unchar b; 1428 1429 ha = HADATA(gdth_ctr_tab[hanum]); 1430 GDTH_LOCK_HA(ha, flags); 1431 1432 for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) { 1433 b = virt_ctr ? NUMDATA(scp->host)->busnum : scp->channel; 1434 if (scp->target == (unchar)id && b == (unchar)busnum) { 1435 TRACE2(("gdth_start_timeout(): update_timeout()\n")); 1436 gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual); 1437 } 1438 } 1439 GDTH_UNLOCK_HA(ha, flags); 1440} 1441 1442static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout) 1443{ 1444 int oldto; 1445 1446 oldto = scp->timeout_per_command; 1447 scp->timeout_per_command = timeout; 1448 1449#if LINUX_VERSION_CODE >= 0x02014B 1450 if (timeout == 0) { 1451 del_timer(&scp->eh_timeout); 1452 scp->eh_timeout.data = (unsigned long) NULL; 1453 scp->eh_timeout.expires = 0; 1454 } else { 1455 if (scp->eh_timeout.data != (unsigned long) NULL) 1456 del_timer(&scp->eh_timeout); 1457 scp->eh_timeout.data = (unsigned long) scp; 1458 scp->eh_timeout.expires = jiffies + timeout; 1459 add_timer(&scp->eh_timeout); 1460 } 1461#else 1462 if (timeout > 0) { 1463 if (timer_table[SCSI_TIMER].expires == 0) { 1464 timer_table[SCSI_TIMER].expires = jiffies + timeout; 1465 timer_active |= 1 << SCSI_TIMER; 1466 } else { 1467 if (time_before(jiffies + timeout, timer_table[SCSI_TIMER].expires)) 1468 timer_table[SCSI_TIMER].expires = jiffies + timeout; 1469 } 1470 } 1471#endif 1472 1473 return oldto; 1474} 1475