1 /* 2 * Copyright (c) 2004-2005 HighPoint Technologies, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/dev/hptmv/ioctl.c,v 1.9 2009/04/07 16:38:25 delphij Exp $ 27 */ 28 /* 29 * ioctl.c ioctl interface implementation 30 */ 31 #include <sys/param.h> 32 #include <sys/systm.h> 33 #include <sys/kernel.h> 34 #include <sys/malloc.h> 35 36 #ifndef __KERNEL__ 37 #define __KERNEL__ 38 #endif 39 40 #include <dev/raid/hptmv/global.h> 41 #include <dev/raid/hptmv/hptintf.h> 42 #include <dev/raid/hptmv/osbsd.h> 43 #include <dev/raid/hptmv/access601.h> 44 45 #pragma pack(1) 46 47 typedef struct _HPT_REBUILD_PARAM 48 { 49 DEVICEID idMirror; 50 DWORD Lba; 51 UCHAR nSector; 52 } HPT_REBUILD_PARAM, *PHPT_REBUILD_PARAM; 53 54 #pragma pack() 55 56 #define MAX_EVENTS 10 57 static HPT_EVENT hpt_event_queue[MAX_EVENTS]; 58 static int event_queue_head=0, event_queue_tail=0; 59 60 static int hpt_get_event(PHPT_EVENT pEvent); 61 static int hpt_set_array_state(DEVICEID idArray, DWORD state); 62 static void lock_driver_idle(IAL_ADAPTER_T *pAdapter); 63 static void HPTLIBAPI thread_io_done(_VBUS_ARG PCommand pCmd); 64 static int HPTLIBAPI R1ControlSgl(_VBUS_ARG PCommand pCmd, 65 FPSCAT_GATH pSgTable, int logical); 66 67 static void 68 get_disk_location(PDevice pDev, int *controller, int *channel) 69 { 70 IAL_ADAPTER_T *pAdapTemp; 71 int i, j; 72 73 *controller = *channel = 0; 74 75 for (i=1, pAdapTemp = gIal_Adapter; pAdapTemp; pAdapTemp = pAdapTemp->next, i++) { 76 for (j=0; j<MV_SATA_CHANNELS_NUM; j++) { 77 if (pDev == &pAdapTemp->VDevices[j].u.disk) { 78 *controller = i; 79 *channel = j; 80 return; 81 } 82 } 83 } 84 } 85 86 static int 87 event_queue_add(PHPT_EVENT pEvent) 88 { 89 int p; 90 p = (event_queue_tail + 1) % MAX_EVENTS; 91 if (p==event_queue_head) 92 { 93 return -1; 94 } 95 hpt_event_queue[event_queue_tail] = *pEvent; 96 event_queue_tail = p; 97 return 0; 98 } 99 100 static int 101 event_queue_remove(PHPT_EVENT pEvent) 102 { 103 if (event_queue_head != event_queue_tail) 104 { 105 *pEvent = hpt_event_queue[event_queue_head]; 106 event_queue_head++; 107 event_queue_head %= MAX_EVENTS; 108 return 0; 109 } 110 return -1; 111 } 112 113 void HPTLIBAPI 114 ioctl_ReportEvent(UCHAR event, PVOID param) 115 { 116 HPT_EVENT e; 117 ZeroMemory(&e, sizeof(e)); 118 e.EventType = event; 119 switch(event) 120 { 121 case ET_INITIALIZE_ABORTED: 122 case ET_INITIALIZE_FAILED: 123 memcpy(e.Data, ((PVDevice)param)->u.array.ArrayName, MAX_ARRAY_NAME); 124 case ET_INITIALIZE_STARTED: 125 case ET_INITIALIZE_FINISHED: 126 127 case ET_REBUILD_STARTED: 128 case ET_REBUILD_ABORTED: 129 case ET_REBUILD_FAILED: 130 case ET_REBUILD_FINISHED: 131 132 case ET_VERIFY_STARTED: 133 case ET_VERIFY_ABORTED: 134 case ET_VERIFY_FAILED: 135 case ET_VERIFY_FINISHED: 136 case ET_VERIFY_DATA_ERROR: 137 138 case ET_SPARE_TOOK_OVER: 139 case ET_DEVICE_REMOVED: 140 case ET_DEVICE_PLUGGED: 141 case ET_DEVICE_ERROR: 142 e.DeviceID = VDEV_TO_ID((PVDevice)param); 143 break; 144 145 default: 146 break; 147 } 148 event_queue_add(&e); 149 if (event==ET_DEVICE_REMOVED) { 150 int controller, channel; 151 get_disk_location(&((PVDevice)param)->u.disk, &controller, &channel); 152 hpt_printk(("Device removed: controller %d channel %d\n", controller, channel)); 153 } 154 } 155 156 static int 157 hpt_delete_array(_VBUS_ARG DEVICEID id, DWORD options) 158 { 159 PVDevice pArray = ID_TO_VDEV(id); 160 BOOLEAN del_block0 = (options & DAF_KEEP_DATA_IF_POSSIBLE)?0:1; 161 int i; 162 PVDevice pa; 163 164 if ((id==0) || check_VDevice_valid(pArray)) 165 return -1; 166 167 if(!mIsArray(pArray)) return -1; 168 169 if (pArray->u.array.rf_rebuilding || pArray->u.array.rf_verifying || 170 pArray->u.array.rf_initializing) 171 return -1; 172 173 for(i=0; i<pArray->u.array.bArnMember; i++) { 174 pa = pArray->u.array.pMember[i]; 175 if (pa && mIsArray(pa)) { 176 if (pa->u.array.rf_rebuilding || pa->u.array.rf_verifying || 177 pa->u.array.rf_initializing) 178 return -1; 179 } 180 } 181 182 if (pArray->pVBus!=_vbus_p) { HPT_ASSERT(0); return -1;} 183 fDeleteArray(_VBUS_P pArray, del_block0); 184 return 0; 185 186 } 187 188 /* just to prevent driver from sending more commands */ 189 static void HPTLIBAPI nothing(_VBUS_ARG void *notused){} 190 191 static void 192 lock_driver_idle(IAL_ADAPTER_T *pAdapter) 193 { 194 _VBUS_INST(&pAdapter->VBus) 195 lock_driver(); 196 while (pAdapter->outstandingCommands) { 197 KdPrint(("outstandingCommands is %d, wait..\n", pAdapter->outstandingCommands)); 198 if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0); 199 unlock_driver(); 200 /*Schedule out*/ 201 tsleep(lock_driver_idle, 0, "switch", 1); 202 lock_driver(); 203 } 204 CheckIdleCall(_VBUS_P0); 205 } 206 207 int Kernel_DeviceIoControl(_VBUS_ARG 208 DWORD dwIoControlCode, /* operation control code */ 209 PVOID lpInBuffer, /* input data buffer */ 210 DWORD nInBufferSize, /* size of input data buffer */ 211 PVOID lpOutBuffer, /* output data buffer */ 212 DWORD nOutBufferSize, /* size of output data buffer */ 213 PDWORD lpBytesReturned /* byte count */ 214 ) 215 { 216 IAL_ADAPTER_T *pAdapter; 217 218 switch(dwIoControlCode) { 219 case HPT_IOCTL_DELETE_ARRAY: 220 { 221 DEVICEID idArray; 222 int iSuccess; 223 int i; 224 PVDevice pArray; 225 PVBus _vbus_p; 226 struct cam_periph *periph = NULL; 227 228 if (nInBufferSize!=sizeof(DEVICEID)+sizeof(DWORD)) return -1; 229 if (nOutBufferSize!=sizeof(int)) return -1; 230 idArray = *(DEVICEID *)lpInBuffer; 231 232 pArray = ID_TO_VDEV(idArray); 233 234 if((idArray == 0) || check_VDevice_valid(pArray)) 235 return -1; 236 237 if(!mIsArray(pArray)) 238 return -1; 239 240 _vbus_p=pArray->pVBus; 241 pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt; 242 243 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) { 244 if(pArray == _vbus_p->pVDevice[i]) 245 { 246 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i); 247 if (periph != NULL && periph->refcount >= 1) 248 { 249 hpt_printk(("Can not delete a mounted device.\n")); 250 return -1; 251 } 252 } 253 /* the Mounted Disk isn't delete */ 254 } 255 256 iSuccess = hpt_delete_array(_VBUS_P idArray, *(DWORD*)((DEVICEID *)lpInBuffer+1)); 257 258 *(int*)lpOutBuffer = iSuccess; 259 260 if(iSuccess != 0) 261 return -1; 262 break; 263 } 264 265 case HPT_IOCTL_GET_EVENT: 266 { 267 PHPT_EVENT pInfo; 268 269 if (nInBufferSize!=0) return -1; 270 if (nOutBufferSize!=sizeof(HPT_EVENT)) return -1; 271 272 pInfo = (PHPT_EVENT)lpOutBuffer; 273 274 if (hpt_get_event(pInfo)!=0) 275 return -1; 276 } 277 break; 278 279 case HPT_IOCTL_SET_ARRAY_STATE: 280 { 281 DEVICEID idArray; 282 DWORD state; 283 284 if (nInBufferSize!=sizeof(HPT_SET_STATE_PARAM)) return -1; 285 if (nOutBufferSize!=0) return -1; 286 287 idArray = ((PHPT_SET_STATE_PARAM)lpInBuffer)->idArray; 288 state = ((PHPT_SET_STATE_PARAM)lpInBuffer)->state; 289 290 if(hpt_set_array_state(idArray, state)!=0) 291 return -1; 292 } 293 break; 294 295 case HPT_IOCTL_RESCAN_DEVICES: 296 { 297 if (nInBufferSize!=0) return -1; 298 if (nOutBufferSize!=0) return -1; 299 300 #ifndef FOR_DEMO 301 /* stop buzzer if user perform rescan */ 302 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) { 303 if (pAdapter->beeping) { 304 pAdapter->beeping = 0; 305 BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress); 306 } 307 } 308 #endif 309 } 310 break; 311 312 default: 313 { 314 PVDevice pVDev; 315 switch(dwIoControlCode) { 316 /* read-only ioctl functions can be called directly. */ 317 case HPT_IOCTL_GET_VERSION: 318 case HPT_IOCTL_GET_CONTROLLER_IDS: 319 case HPT_IOCTL_GET_CONTROLLER_COUNT: 320 case HPT_IOCTL_GET_CONTROLLER_INFO: 321 case HPT_IOCTL_GET_CHANNEL_INFO: 322 case HPT_IOCTL_GET_LOGICAL_DEVICES: 323 case HPT_IOCTL_GET_DEVICE_INFO: 324 case HPT_IOCTL_GET_DEVICE_INFO_V2: 325 case HPT_IOCTL_GET_EVENT: 326 case HPT_IOCTL_GET_DRIVER_CAPABILITIES: 327 if(hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize, 328 lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) return -1; 329 break; 330 331 default: 332 /* 333 * GUI always use /proc/scsi/hptmv/0, so the _vbus_p param will be 334 * wrong for second controller. 335 */ 336 switch(dwIoControlCode) { 337 case HPT_IOCTL_CREATE_ARRAY: 338 pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS)lpInBuffer)->Members[0]); break; 339 case HPT_IOCTL_CREATE_ARRAY_V2: 340 pVDev = ID_TO_VDEV(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->Members[0]); break; 341 case HPT_IOCTL_SET_ARRAY_INFO: 342 pVDev = ID_TO_VDEV(((PHPT_SET_ARRAY_INFO)lpInBuffer)->idArray); break; 343 case HPT_IOCTL_SET_DEVICE_INFO: 344 pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO)lpInBuffer)->idDisk); break; 345 case HPT_IOCTL_SET_DEVICE_INFO_V2: 346 pVDev = ID_TO_VDEV(((PHPT_SET_DEVICE_INFO_V2)lpInBuffer)->idDisk); break; 347 case HPT_IOCTL_SET_BOOT_MARK: 348 case HPT_IOCTL_ADD_SPARE_DISK: 349 case HPT_IOCTL_REMOVE_SPARE_DISK: 350 pVDev = ID_TO_VDEV(*(DEVICEID *)lpInBuffer); break; 351 case HPT_IOCTL_ADD_DISK_TO_ARRAY: 352 pVDev = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); break; 353 default: 354 pVDev = 0; 355 } 356 357 if (pVDev && !check_VDevice_valid(pVDev)){ 358 _vbus_p = pVDev->pVBus; 359 360 pAdapter = (IAL_ADAPTER_T *)_vbus_p->OsExt; 361 /* 362 * create_array, and other functions can't be executed while channel is 363 * perform I/O commands. Wait until driver is idle. 364 */ 365 lock_driver_idle(pAdapter); 366 if (hpt_default_ioctl(_VBUS_P dwIoControlCode, lpInBuffer, nInBufferSize, 367 lpOutBuffer, nOutBufferSize, lpBytesReturned) == -1) { 368 unlock_driver(); 369 return -1; 370 } 371 unlock_driver(); 372 } 373 else 374 return -1; 375 break; 376 } 377 378 #ifdef SUPPORT_ARRAY 379 switch(dwIoControlCode) 380 { 381 case HPT_IOCTL_CREATE_ARRAY: 382 { 383 pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt; 384 lock_driver(); 385 if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) 386 { 387 (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0; 388 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE); 389 } 390 else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) 391 { 392 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE); 393 } 394 else if(((PCREATE_ARRAY_PARAMS)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) 395 { 396 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY); 397 } 398 unlock_driver(); 399 break; 400 } 401 402 403 case HPT_IOCTL_CREATE_ARRAY_V2: 404 { 405 pAdapter=(IAL_ADAPTER_T *)(ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->pVBus->OsExt; 406 lock_driver(); 407 if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_AND_DUPLICATE) { 408 (ID_TO_VDEV(*(DEVICEID *)lpOutBuffer))->u.array.rf_auto_rebuild = 0; 409 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), DUPLICATE); 410 } else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_ZERO_INIT) { 411 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), INITIALIZE); 412 } else if(((PCREATE_ARRAY_PARAMS_V2)lpInBuffer)->CreateFlags & CAF_CREATE_R5_BUILD_PARITY) { 413 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, ID_TO_VDEV(*(DEVICEID *)lpOutBuffer), REBUILD_PARITY); 414 } 415 unlock_driver(); 416 break; 417 } 418 case HPT_IOCTL_ADD_DISK_TO_ARRAY: 419 { 420 PVDevice pArray = ID_TO_VDEV(((PHPT_ADD_DISK_TO_ARRAY)lpInBuffer)->idArray); 421 pAdapter=(IAL_ADAPTER_T *)pArray->pVBus->OsExt; 422 if(pArray->u.array.rf_rebuilding == 0) 423 { 424 DWORD timeout = 0; 425 lock_driver(); 426 pArray->u.array.rf_auto_rebuild = 0; 427 pArray->u.array.rf_abort_rebuild = 0; 428 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE); 429 unlock_driver(); 430 while (!pArray->u.array.rf_rebuilding) 431 { 432 tsleep((caddr_t)Kernel_DeviceIoControl, 0, "pause", 1); 433 if ( timeout >= hz*3) 434 break; 435 timeout ++; 436 } 437 } 438 break; 439 } 440 } 441 #endif 442 return 0; 443 } 444 } 445 446 if (lpBytesReturned) 447 *lpBytesReturned = nOutBufferSize; 448 return 0; 449 } 450 451 static int 452 hpt_get_event(PHPT_EVENT pEvent) 453 { 454 lock_driver(); 455 int ret = event_queue_remove(pEvent); 456 unlock_driver(); 457 return ret; 458 } 459 460 static int 461 hpt_set_array_state(DEVICEID idArray, DWORD state) 462 { 463 IAL_ADAPTER_T *pAdapter; 464 PVDevice pVDevice = ID_TO_VDEV(idArray); 465 int i; 466 DWORD timeout = 0; 467 468 if(idArray == 0 || check_VDevice_valid(pVDevice)) return -1; 469 if(!mIsArray(pVDevice)) 470 return -1; 471 if(!pVDevice->vf_online || pVDevice->u.array.rf_broken) return -1; 472 473 pAdapter=(IAL_ADAPTER_T *)pVDevice->pVBus->OsExt; 474 475 switch(state) 476 { 477 case MIRROR_REBUILD_START: 478 { 479 if (pVDevice->u.array.rf_rebuilding || 480 pVDevice->u.array.rf_verifying || 481 pVDevice->u.array.rf_initializing) 482 return -1; 483 484 lock_driver(); 485 486 pVDevice->u.array.rf_auto_rebuild = 0; 487 pVDevice->u.array.rf_abort_rebuild = 0; 488 489 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, 490 (UCHAR)((pVDevice->u.array.CriticalMembers || pVDevice->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY)); 491 492 unlock_driver(); 493 494 while (!pVDevice->u.array.rf_rebuilding) 495 { 496 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); 497 if ( timeout >= hz*20) 498 break; 499 timeout ++; 500 } 501 } 502 503 break; 504 505 case MIRROR_REBUILD_ABORT: 506 { 507 for(i = 0; i < pVDevice->u.array.bArnMember; i++) { 508 if(pVDevice->u.array.pMember[i] != 0 && pVDevice->u.array.pMember[i]->VDeviceType == VD_RAID_1) 509 hpt_set_array_state(VDEV_TO_ID(pVDevice->u.array.pMember[i]), state); 510 } 511 512 if(pVDevice->u.array.rf_rebuilding != 1) 513 return -1; 514 515 lock_driver(); 516 pVDevice->u.array.rf_abort_rebuild = 1; 517 unlock_driver(); 518 519 while (pVDevice->u.array.rf_abort_rebuild) 520 { 521 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); 522 if ( timeout >= hz*20) 523 break; 524 timeout ++; 525 } 526 } 527 break; 528 529 case AS_VERIFY_START: 530 { 531 /*if(pVDevice->u.array.rf_verifying) 532 return -1;*/ 533 if (pVDevice->u.array.rf_rebuilding || 534 pVDevice->u.array.rf_verifying || 535 pVDevice->u.array.rf_initializing) 536 return -1; 537 538 lock_driver(); 539 pVDevice->u.array.RebuildSectors = 0; 540 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY); 541 unlock_driver(); 542 543 while (!pVDevice->u.array.rf_verifying) 544 { 545 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); 546 if ( timeout >= hz*20) 547 break; 548 timeout ++; 549 } 550 } 551 break; 552 553 case AS_VERIFY_ABORT: 554 { 555 if(pVDevice->u.array.rf_verifying != 1) 556 return -1; 557 558 lock_driver(); 559 pVDevice->u.array.rf_abort_rebuild = 1; 560 unlock_driver(); 561 562 while (pVDevice->u.array.rf_abort_rebuild) 563 { 564 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); 565 if ( timeout >= hz*80) 566 break; 567 timeout ++; 568 } 569 } 570 break; 571 572 case AS_INITIALIZE_START: 573 { 574 if (pVDevice->u.array.rf_rebuilding || 575 pVDevice->u.array.rf_verifying || 576 pVDevice->u.array.rf_initializing) 577 return -1; 578 579 lock_driver(); 580 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pVDevice, VERIFY); 581 unlock_driver(); 582 583 while (!pVDevice->u.array.rf_initializing) 584 { 585 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); 586 if ( timeout >= hz*80) 587 break; 588 timeout ++; 589 } 590 } 591 break; 592 593 case AS_INITIALIZE_ABORT: 594 { 595 if(pVDevice->u.array.rf_initializing != 1) 596 return -1; 597 598 lock_driver(); 599 pVDevice->u.array.rf_abort_rebuild = 1; 600 unlock_driver(); 601 602 while (pVDevice->u.array.rf_abort_rebuild) 603 { 604 tsleep((caddr_t)hpt_set_array_state, 0, "pause", 1); 605 if ( timeout >= hz*80) 606 break; 607 timeout ++; 608 } 609 } 610 break; 611 612 default: 613 return -1; 614 } 615 616 return 0; 617 } 618 619 static int HPTLIBAPI 620 R1ControlSgl(_VBUS_ARG PCommand pCmd, FPSCAT_GATH pSgTable, int logical) 621 { 622 ULONG bufferSize = SECTOR_TO_BYTE(pCmd->uCmd.R1Control.nSectors); 623 if (pCmd->uCmd.R1Control.Command==CTRL_CMD_VERIFY) 624 bufferSize<<=1; 625 if (logical) { 626 pSgTable->dSgAddress = (ULONG_PTR)pCmd->uCmd.R1Control.Buffer; 627 pSgTable->wSgSize = (USHORT)bufferSize; 628 pSgTable->wSgFlag = SG_FLAG_EOT; 629 } 630 else { 631 /* build physical SG table for pCmd->uCmd.R1Control.Buffer */ 632 ADDRESS dataPointer, v, nextpage, currvaddr, nextvaddr, currphypage, nextphypage; 633 ULONG length; 634 int idx = 0; 635 636 v = pCmd->uCmd.R1Control.Buffer; 637 dataPointer = (ADDRESS)fOsPhysicalAddress(v); 638 639 if ((ULONG_PTR)dataPointer & 0x1) 640 return FALSE; 641 642 #define ON64KBOUNDARY(x) (((ULONG_PTR)(x) & 0xFFFF) == 0) 643 #define NOTNEIGHBORPAGE(highvaddr, lowvaddr) ((ULONG_PTR)(highvaddr) - (ULONG_PTR)(lowvaddr) != PAGE_SIZE) 644 645 do { 646 if (idx >= MAX_SG_DESCRIPTORS) return FALSE; 647 648 pSgTable[idx].dSgAddress = fOsPhysicalAddress(v); 649 currvaddr = v; 650 currphypage = (ADDRESS)fOsPhysicalAddress((void*)trunc_page((ULONG_PTR)currvaddr)); 651 652 653 do { 654 nextpage = (ADDRESS)trunc_page(((ULONG_PTR)currvaddr + PAGE_SIZE)); 655 nextvaddr = (ADDRESS)MIN(((ULONG_PTR)v + bufferSize), (ULONG_PTR)(nextpage)); 656 657 if (nextvaddr == (ADDRESS)((ULONG_PTR)v + bufferSize)) break; 658 nextphypage = (ADDRESS)fOsPhysicalAddress(nextpage); 659 660 if (NOTNEIGHBORPAGE(nextphypage, currphypage) || ON64KBOUNDARY(nextphypage)) { 661 nextvaddr = nextpage; 662 break; 663 } 664 665 currvaddr = nextvaddr; 666 currphypage = nextphypage; 667 }while (1); 668 669 length = (ULONG_PTR)nextvaddr - (ULONG_PTR)v; 670 v = nextvaddr; 671 bufferSize -= length; 672 673 pSgTable[idx].wSgSize = (USHORT)length; 674 pSgTable[idx].wSgFlag = (bufferSize)? 0 : SG_FLAG_EOT; 675 idx++; 676 677 }while (bufferSize); 678 } 679 return 1; 680 } 681 682 static int End_Job=0; 683 static void HPTLIBAPI 684 thread_io_done(_VBUS_ARG PCommand pCmd) 685 { 686 End_Job = 1; 687 wakeup((caddr_t)pCmd); 688 } 689 690 void 691 hpt_rebuild_data_block(IAL_ADAPTER_T *pAdapter, PVDevice pArray, UCHAR flags) 692 { 693 DWORD timeout = 0; 694 ULONG capacity = pArray->VDeviceCapacity / (pArray->u.array.bArnMember-1); 695 PCommand pCmd; 696 UINT result; 697 int needsync=0, retry=0, needdelete=0; 698 void *buffer = NULL; 699 700 _VBUS_INST(&pAdapter->VBus) 701 702 if (pArray->u.array.rf_broken==1 || 703 pArray->u.array.RebuildSectors>=capacity) 704 return; 705 706 lock_driver(); 707 708 switch(flags) 709 { 710 case DUPLICATE: 711 case REBUILD_PARITY: 712 if(pArray->u.array.rf_rebuilding == 0) 713 { 714 pArray->u.array.rf_rebuilding = 1; 715 hpt_printk(("Rebuilding started.\n")); 716 ioctl_ReportEvent(ET_REBUILD_STARTED, pArray); 717 } 718 break; 719 720 case INITIALIZE: 721 if(pArray->u.array.rf_initializing == 0) 722 { 723 pArray->u.array.rf_initializing = 1; 724 hpt_printk(("Initializing started.\n")); 725 ioctl_ReportEvent(ET_INITIALIZE_STARTED, pArray); 726 } 727 break; 728 729 case VERIFY: 730 if(pArray->u.array.rf_verifying == 0) 731 { 732 pArray->u.array.rf_verifying = 1; 733 hpt_printk(("Verifying started.\n")); 734 ioctl_ReportEvent(ET_VERIFY_STARTED, pArray); 735 } 736 break; 737 } 738 739 retry_cmd: 740 pCmd = AllocateCommand(_VBUS_P0); 741 HPT_ASSERT(pCmd); 742 pCmd->cf_control = 1; 743 End_Job = 0; 744 745 if (pArray->VDeviceType==VD_RAID_1) 746 { 747 #define MAX_REBUILD_SECTORS 0x40 748 749 /* take care for discontinuous buffer in R1ControlSgl */ 750 unlock_driver(); 751 buffer = kmalloc(SECTOR_TO_BYTE(MAX_REBUILD_SECTORS), M_DEVBUF, M_NOWAIT); 752 lock_driver(); 753 if(!buffer) { 754 FreeCommand(_VBUS_P pCmd); 755 hpt_printk(("can't allocate rebuild buffer\n")); 756 goto fail; 757 } 758 switch(flags) 759 { 760 case DUPLICATE: 761 pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD; 762 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS; 763 break; 764 765 case VERIFY: 766 pCmd->uCmd.R1Control.Command = CTRL_CMD_VERIFY; 767 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS/2; 768 break; 769 770 case INITIALIZE: 771 pCmd->uCmd.R1Control.Command = CTRL_CMD_REBUILD; 772 pCmd->uCmd.R1Control.nSectors = MAX_REBUILD_SECTORS; 773 break; 774 } 775 776 pCmd->uCmd.R1Control.Lba = pArray->u.array.RebuildSectors; 777 778 if (capacity - pArray->u.array.RebuildSectors < pCmd->uCmd.R1Control.nSectors) 779 pCmd->uCmd.R1Control.nSectors = capacity - pArray->u.array.RebuildSectors; 780 781 pCmd->uCmd.R1Control.Buffer = buffer; 782 pCmd->pfnBuildSgl = R1ControlSgl; 783 } 784 else if (pArray->VDeviceType==VD_RAID_5) 785 { 786 switch(flags) 787 { 788 case DUPLICATE: 789 case REBUILD_PARITY: 790 pCmd->uCmd.R5Control.Command = CTRL_CMD_REBUILD; break; 791 case VERIFY: 792 pCmd->uCmd.R5Control.Command = CTRL_CMD_VERIFY; break; 793 case INITIALIZE: 794 pCmd->uCmd.R5Control.Command = CTRL_CMD_INIT; break; 795 } 796 pCmd->uCmd.R5Control.StripeLine=pArray->u.array.RebuildSectors>>pArray->u.array.bArBlockSizeShift; 797 } 798 else 799 HPT_ASSERT(0); 800 801 pCmd->pVDevice = pArray; 802 pCmd->pfnCompletion = thread_io_done; 803 pArray->pfnSendCommand(_VBUS_P pCmd); 804 CheckPendingCall(_VBUS_P0); 805 806 if (!End_Job) { 807 unlock_driver(); 808 while (!End_Job) { 809 tsleep((caddr_t)pCmd, 0, "pause", hz); 810 if (timeout++>60) break; 811 } 812 lock_driver(); 813 if (!End_Job) { 814 hpt_printk(("timeout, reset\n")); 815 fResetVBus(_VBUS_P0); 816 } 817 } 818 819 result = pCmd->Result; 820 FreeCommand(_VBUS_P pCmd); 821 unlock_driver(); 822 if (buffer) kfree(buffer, M_DEVBUF); 823 lock_driver(); 824 KdPrintI(("cmd finished %d", result)); 825 826 switch(result) 827 { 828 case RETURN_SUCCESS: 829 if (!pArray->u.array.rf_abort_rebuild) 830 { 831 if(pArray->u.array.RebuildSectors < capacity) 832 { 833 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, flags); 834 } 835 else 836 { 837 switch (flags) 838 { 839 case DUPLICATE: 840 case REBUILD_PARITY: 841 needsync = 1; 842 pArray->u.array.rf_rebuilding = 0; 843 pArray->u.array.rf_need_rebuild = 0; 844 pArray->u.array.CriticalMembers = 0; 845 pArray->u.array.RebuildSectors = MAX_LBA_T; 846 pArray->u.array.rf_duplicate_and_create = 0; 847 hpt_printk(("Rebuilding finished.\n")); 848 ioctl_ReportEvent(ET_REBUILD_FINISHED, pArray); 849 break; 850 case INITIALIZE: 851 needsync = 1; 852 pArray->u.array.rf_initializing = 0; 853 pArray->u.array.rf_need_rebuild = 0; 854 pArray->u.array.RebuildSectors = MAX_LBA_T; 855 hpt_printk(("Initializing finished.\n")); 856 ioctl_ReportEvent(ET_INITIALIZE_FINISHED, pArray); 857 break; 858 case VERIFY: 859 pArray->u.array.rf_verifying = 0; 860 hpt_printk(("Verifying finished.\n")); 861 ioctl_ReportEvent(ET_VERIFY_FINISHED, pArray); 862 break; 863 } 864 } 865 } 866 else 867 { 868 pArray->u.array.rf_abort_rebuild = 0; 869 if (pArray->u.array.rf_rebuilding) 870 { 871 hpt_printk(("Abort rebuilding.\n")); 872 pArray->u.array.rf_rebuilding = 0; 873 pArray->u.array.rf_duplicate_and_create = 0; 874 ioctl_ReportEvent(ET_REBUILD_ABORTED, pArray); 875 } 876 else if (pArray->u.array.rf_verifying) 877 { 878 hpt_printk(("Abort verifying.\n")); 879 pArray->u.array.rf_verifying = 0; 880 ioctl_ReportEvent(ET_VERIFY_ABORTED, pArray); 881 } 882 else if (pArray->u.array.rf_initializing) 883 { 884 hpt_printk(("Abort initializing.\n")); 885 pArray->u.array.rf_initializing = 0; 886 ioctl_ReportEvent(ET_INITIALIZE_ABORTED, pArray); 887 } 888 needdelete=1; 889 } 890 break; 891 892 case RETURN_DATA_ERROR: 893 if (flags==VERIFY) 894 { 895 needsync = 1; 896 pArray->u.array.rf_verifying = 0; 897 pArray->u.array.rf_need_rebuild = 1; 898 hpt_printk(("Verifying failed: found inconsistency\n")); 899 ioctl_ReportEvent(ET_VERIFY_DATA_ERROR, pArray); 900 ioctl_ReportEvent(ET_VERIFY_FAILED, pArray); 901 902 if (!pArray->vf_online || pArray->u.array.rf_broken) break; 903 904 pArray->u.array.rf_auto_rebuild = 0; 905 pArray->u.array.rf_abort_rebuild = 0; 906 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, 907 (pArray->VDeviceType == VD_RAID_1) ? DUPLICATE : REBUILD_PARITY); 908 } 909 break; 910 911 default: 912 hpt_printk(("command failed with error %d\n", result)); 913 if (++retry<3) 914 { 915 hpt_printk(("retry (%d)\n", retry)); 916 goto retry_cmd; 917 } 918 fail: 919 pArray->u.array.rf_abort_rebuild = 0; 920 switch (flags) 921 { 922 case DUPLICATE: 923 case REBUILD_PARITY: 924 needsync = 1; 925 pArray->u.array.rf_rebuilding = 0; 926 pArray->u.array.rf_duplicate_and_create = 0; 927 hpt_printk(((flags==DUPLICATE)? "Duplicating failed.\n":"Rebuilding failed.\n")); 928 ioctl_ReportEvent(ET_REBUILD_FAILED, pArray); 929 break; 930 931 case INITIALIZE: 932 needsync = 1; 933 pArray->u.array.rf_initializing = 0; 934 hpt_printk(("Initializing failed.\n")); 935 ioctl_ReportEvent(ET_INITIALIZE_FAILED, pArray); 936 break; 937 938 case VERIFY: 939 needsync = 1; 940 pArray->u.array.rf_verifying = 0; 941 hpt_printk(("Verifying failed.\n")); 942 ioctl_ReportEvent(ET_VERIFY_FAILED, pArray); 943 break; 944 } 945 needdelete=1; 946 } 947 948 while (pAdapter->outstandingCommands) 949 { 950 KdPrintI(("currcmds is %d, wait..\n", pAdapter->outstandingCommands)); 951 /* put this to have driver stop processing system commands quickly */ 952 if (!mWaitingForIdle(_VBUS_P0)) CallWhenIdle(_VBUS_P nothing, 0); 953 unlock_driver(); 954 /*Schedule out*/ 955 tsleep(hpt_rebuild_data_block, 0, "switch", 1); 956 lock_driver(); 957 } 958 959 if (needsync) SyncArrayInfo(pArray); 960 if(needdelete && (pArray->u.array.rf_duplicate_must_done || (flags == INITIALIZE))) 961 fDeleteArray(_VBUS_P pArray, TRUE); 962 963 Check_Idle_Call(pAdapter); 964 unlock_driver(); 965 } 966