1 /* 2 * Copyright (c) 2003-2004 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 /* 27 * hptproc.c sysctl support 28 */ 29 #include <sys/param.h> 30 #include <sys/systm.h> 31 #include <sys/kernel.h> 32 #include <sys/malloc.h> 33 #include <sys/sysctl.h> 34 #include <machine/stdarg.h> 35 36 #include <dev/hptmv/global.h> 37 #include <dev/hptmv/hptintf.h> 38 #include <dev/hptmv/osbsd.h> 39 #include <contrib/dev/hptmv/access601.h> 40 41 int hpt_rescan_all(void); 42 43 /***************************************************************************/ 44 45 static char hptproc_buffer[256]; 46 47 #define FORMAL_HANDLER_ARGS struct sysctl_oid *oidp, void *arg1, int arg2, \ 48 struct sysctl_req *req 49 #define REAL_HANDLER_ARGS oidp, arg1, arg2, req 50 typedef struct sysctl_req HPT_GET_INFO; 51 52 static int hpt_set_asc_info(IAL_ADAPTER_T *pAdapter, char *buffer,int length) 53 { 54 int orig_length = length+4; 55 PVBus _vbus_p = &pAdapter->VBus; 56 PVDevice pArray; 57 PVDevice pSubArray, pVDev; 58 UINT i, iarray, ichan; 59 struct cam_periph *periph = NULL; 60 intrmask_t oldspl; 61 62 #ifdef SUPPORT_ARRAY 63 if (length>=8 && strncmp(buffer, "rebuild ", 8)==0) 64 { 65 buffer+=8; 66 length-=8; 67 if (length>=5 && strncmp(buffer, "start", 5)==0) 68 { 69 oldspl = lock_driver(); 70 for(i = 0; i < MAX_ARRAY_PER_VBUS; i++) 71 if ((pArray=ArrayTables(i))->u.array.dArStamp==0) 72 continue; 73 else{ 74 if (pArray->u.array.rf_need_rebuild && !pArray->u.array.rf_rebuilding) 75 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, 76 (UCHAR)((pArray->u.array.CriticalMembers || pArray->VDeviceType == VD_RAID_1)? DUPLICATE : REBUILD_PARITY)); 77 } 78 unlock_driver(oldspl); 79 return orig_length; 80 } 81 else if (length>=4 && strncmp(buffer, "stop", 4)==0) 82 { 83 oldspl = lock_driver(); 84 for(i = 0; i < MAX_ARRAY_PER_VBUS; i++) 85 if ((pArray=ArrayTables(i))->u.array.dArStamp==0) 86 continue; 87 else{ 88 if (pArray->u.array.rf_rebuilding) 89 pArray->u.array.rf_abort_rebuild = 1; 90 } 91 unlock_driver(oldspl); 92 return orig_length; 93 } 94 else if (length>=3 && buffer[1]==','&& buffer[0]>='1'&& buffer[2]>='1') 95 { 96 iarray = buffer[0]-'1'; 97 ichan = buffer[2]-'1'; 98 99 if(iarray >= MAX_VDEVICE_PER_VBUS || ichan >= MV_SATA_CHANNELS_NUM) return -EINVAL; 100 101 pArray = _vbus_p->pVDevice[iarray]; 102 if (!pArray || (pArray->vf_online == 0)) return -EINVAL; 103 104 for (i=0;i<MV_SATA_CHANNELS_NUM;i++) 105 if(i == ichan) 106 goto rebuild; 107 108 return -EINVAL; 109 110 rebuild: 111 pVDev = &pAdapter->VDevices[ichan]; 112 if(!pVDev->u.disk.df_on_line || pVDev->pParent) return -EINVAL; 113 114 /* Not allow to use a mounted disk ??? test*/ 115 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++) 116 if(pVDev == _vbus_p->pVDevice[i]) 117 { 118 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId,i); 119 if (periph != NULL && periph->refcount == 1) 120 { 121 hpt_printk(("Can not use disk used by OS!\n")); 122 return -EINVAL; 123 } 124 /* the Mounted Disk isn't delete */ 125 } 126 127 switch(pArray->VDeviceType) 128 { 129 case VD_RAID_1: 130 case VD_RAID_5: 131 { 132 pSubArray = pArray; 133 loop: 134 oldspl = lock_driver(); 135 if(hpt_add_disk_to_array(_VBUS_P VDEV_TO_ID(pSubArray), VDEV_TO_ID(pVDev)) == -1) { 136 unlock_driver(oldspl); 137 return -EINVAL; 138 } 139 pArray->u.array.rf_auto_rebuild = 0; 140 pArray->u.array.rf_abort_rebuild = 0; 141 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, DUPLICATE); 142 unlock_driver(oldspl); 143 break; 144 } 145 case VD_RAID_0: 146 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) 147 if(pArray->u.array.pMember[i] && mIsArray(pArray->u.array.pMember[i]) && 148 (pArray->u.array.pMember[i]->u.array.rf_broken == 1)) 149 { 150 pSubArray = pArray->u.array.pMember[i]; 151 goto loop; 152 } 153 default: 154 return -EINVAL; 155 } 156 return orig_length; 157 } 158 } 159 else if (length>=7 && strncmp(buffer, "verify ", 7)==0) 160 { 161 buffer+=7; 162 length-=7; 163 if (length>=6 && strncmp(buffer, "start ", 6)==0) 164 { 165 buffer+=6; 166 length-=6; 167 if (length>=1 && *buffer>='1') 168 { 169 iarray = *buffer-'1'; 170 if(iarray >= MAX_VDEVICE_PER_VBUS) return -EINVAL; 171 172 pArray = _vbus_p->pVDevice[iarray]; 173 if (!pArray || (pArray->vf_online == 0)) return -EINVAL; 174 175 if(pArray->VDeviceType != VD_RAID_1 && pArray->VDeviceType != VD_RAID_5) 176 return -EINVAL; 177 178 if (!(pArray->u.array.rf_need_rebuild || 179 pArray->u.array.rf_rebuilding || 180 pArray->u.array.rf_verifying || 181 pArray->u.array.rf_initializing)) 182 { 183 oldspl = lock_driver(); 184 pArray->u.array.RebuildSectors = 0; 185 hpt_queue_dpc((HPT_DPC)hpt_rebuild_data_block, pAdapter, pArray, VERIFY); 186 unlock_driver(oldspl); 187 } 188 return orig_length; 189 } 190 } 191 else if (length>=5 && strncmp(buffer, "stop ", 5)==0) 192 { 193 buffer+=5; 194 length-=5; 195 if (length>=1 && *buffer>='1') 196 { 197 iarray = *buffer-'1'; 198 if(iarray >= MAX_VDEVICE_PER_VBUS) return -EINVAL; 199 200 pArray = _vbus_p->pVDevice[iarray]; 201 if (!pArray || (pArray->vf_online == 0)) return -EINVAL; 202 if(pArray->u.array.rf_verifying) 203 { 204 oldspl = lock_driver(); 205 pArray->u.array.rf_abort_rebuild = 1; 206 unlock_driver(oldspl); 207 } 208 return orig_length; 209 } 210 } 211 } 212 else 213 #ifdef _RAID5N_ 214 if (length>=10 && strncmp(buffer, "writeback ", 10)==0) { 215 buffer+=10; 216 length-=10; 217 if (length>=1 && *buffer>='0' && *buffer<='1') { 218 _vbus_(r5.enable_write_back) = *buffer-'0'; 219 if (_vbus_(r5.enable_write_back)) 220 hpt_printk(("RAID5 write back enabled")); 221 return orig_length; 222 } 223 } 224 else 225 #endif 226 #endif /* SUPPORT_ARRAY */ 227 if (0) {} /* just to compile */ 228 #if DBGUG 229 else if (length>=9 && strncmp(buffer, "dbglevel ", 9)==0) { 230 buffer+=9; 231 length-=9; 232 if (length>=1 && *buffer>='0' && *buffer<='3') { 233 hpt_dbg_level = *buffer-'0'; 234 return orig_length; 235 } 236 } 237 else if (length>=8 && strncmp(buffer, "disable ", 8)==0) { 238 /* TO DO */ 239 } 240 #endif 241 242 return -EINVAL; 243 } 244 245 /* 246 * Since we have only one sysctl node, add adapter ID in the command 247 * line string: e.g. "hpt 0 rebuild start" 248 */ 249 static int hpt_set_info(int length) 250 { 251 int retval; 252 253 #ifdef SUPPORT_IOCTL 254 PUCHAR ke_area; 255 int err; 256 DWORD dwRet; 257 PHPT_IOCTL_PARAM32 piop; 258 #endif 259 char *buffer = hptproc_buffer; 260 if (length >= 6) { 261 if (strncmp(buffer,"hpt ",4) == 0) { 262 IAL_ADAPTER_T *pAdapter; 263 retval = buffer[4]-'0'; 264 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) { 265 if (pAdapter->mvSataAdapter.adapterId==retval) 266 return (retval = hpt_set_asc_info(pAdapter, buffer+6, length-6)) >= 0? retval : -EINVAL; 267 } 268 return -EINVAL; 269 } 270 #ifdef SUPPORT_IOCTL 271 piop = (PHPT_IOCTL_PARAM32)buffer; 272 if (piop->Magic == HPT_IOCTL_MAGIC) { 273 KdPrintE(("ioctl=%d in=%x len=%d out=%x len=%ld\n", 274 piop->dwIoControlCode, 275 piop->lpInBuffer, 276 piop->nInBufferSize, 277 piop->lpOutBuffer, 278 (u_long)piop->nOutBufferSize)); 279 280 /* 281 * map buffer to kernel. 282 */ 283 if (piop->nInBufferSize+piop->nOutBufferSize > PAGE_SIZE) { 284 KdPrintE(("User buffer too large\n")); 285 return -EINVAL; 286 } 287 288 ke_area = malloc(piop->nInBufferSize+piop->nOutBufferSize, M_DEVBUF, M_NOWAIT); 289 if (ke_area == NULL) { 290 KdPrintE(("Couldn't allocate kernel mem.\n")); 291 return -EINVAL; 292 } 293 294 if (piop->nInBufferSize) 295 copyin((void*)(ULONG_PTR)piop->lpInBuffer, ke_area, piop->nInBufferSize); 296 297 /* 298 * call kernel handler. 299 */ 300 err = Kernel_DeviceIoControl(&gIal_Adapter->VBus, 301 piop->dwIoControlCode, ke_area, piop->nInBufferSize, 302 ke_area + piop->nInBufferSize, piop->nOutBufferSize, &dwRet); 303 304 if (err==0) { 305 if (piop->nOutBufferSize) 306 copyout(ke_area + piop->nInBufferSize, (void*)(ULONG_PTR)piop->lpOutBuffer, piop->nOutBufferSize); 307 308 if (piop->lpBytesReturned) 309 copyout(&dwRet, (void*)(ULONG_PTR)piop->lpBytesReturned, sizeof(DWORD)); 310 311 free(ke_area, M_DEVBUF); 312 return length; 313 } 314 else KdPrintW(("Kernel_ioctl(): return %d\n", err)); 315 316 free(ke_area, M_DEVBUF); 317 return -EINVAL; 318 } else { 319 KdPrintW(("Wrong signature: %x\n", piop->Magic)); 320 return -EINVAL; 321 } 322 #endif 323 } 324 325 return -EINVAL; 326 } 327 328 #define shortswap(w) ((WORD)((w)>>8 | ((w) & 0xFF)<<8)) 329 330 static void get_disk_name(char *name, PDevice pDev) 331 { 332 int i; 333 MV_SATA_CHANNEL *pMvSataChannel = pDev->mv; 334 IDENTIFY_DATA2 *pIdentifyData = (IDENTIFY_DATA2 *)pMvSataChannel->identifyDevice; 335 336 for (i = 0; i < 10; i++) 337 ((WORD*)name)[i] = shortswap(pIdentifyData->ModelNumber[i]); 338 name[20] = '\0'; 339 } 340 341 static int hpt_copy_info(HPT_GET_INFO *pinfo, char *fmt, ...) 342 { 343 int printfretval; 344 va_list ap; 345 346 if(fmt == NULL) { 347 *hptproc_buffer = 0; 348 return (SYSCTL_OUT(pinfo, hptproc_buffer, 1)); 349 } 350 else 351 { 352 va_start(ap, fmt); 353 printfretval = vsnprintf(hptproc_buffer, sizeof(hptproc_buffer), fmt, ap); 354 va_end(ap); 355 return(SYSCTL_OUT(pinfo, hptproc_buffer, strlen(hptproc_buffer))); 356 } 357 } 358 359 static void hpt_copy_disk_info(HPT_GET_INFO *pinfo, PVDevice pVDev, UINT iChan) 360 { 361 char name[32], arrayname[16]; 362 363 get_disk_name(name, &pVDev->u.disk); 364 365 #ifdef SUPPORT_ARRAY 366 if(pVDev->pParent) 367 memcpy(arrayname, pVDev->pParent->u.array.ArrayName, MAX_ARRAY_NAME); 368 else 369 #endif 370 arrayname[0]=0; 371 372 hpt_copy_info(pinfo, "Channel %d %s %5dMB %s %s\n", 373 iChan+1, 374 name, pVDev->VDeviceCapacity>>11, 375 ((!pVDev->u.disk.df_on_line)? "Disabled" : 376 ((pVDev->VDeviceType != VD_SPARE)?"Normal ":"Spare ")), arrayname); 377 } 378 379 #ifdef SUPPORT_ARRAY 380 static void hpt_copy_array_info(HPT_GET_INFO *pinfo, int nld, PVDevice pArray) 381 { 382 int i; 383 char *sType=0, *sStatus=0; 384 char buf[32]; 385 PVDevice pTmpArray; 386 387 switch (pArray->VDeviceType) { 388 case VD_RAID_0: 389 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) 390 if(pArray->u.array.pMember[i]) { 391 if(mIsArray(pArray->u.array.pMember[i])) 392 sType = "RAID 1/0 "; 393 /* TO DO */ 394 else 395 sType = "RAID 0 "; 396 break; 397 } 398 break; 399 400 case VD_RAID_1: 401 sType = "RAID 1 "; 402 break; 403 404 case VD_JBOD: 405 sType = "JBOD "; 406 break; 407 408 case VD_RAID_5: 409 sType = "RAID 5 "; 410 break; 411 412 default: 413 sType = "N/A "; 414 break; 415 } 416 417 if (pArray->vf_online == 0) 418 sStatus = "Disabled"; 419 else if (pArray->u.array.rf_broken) 420 sStatus = "Critical"; 421 for (i = 0; (UCHAR)i < pArray->u.array.bArnMember; i++) 422 { 423 if (!sStatus) 424 { 425 if(mIsArray(pArray->u.array.pMember[i])) 426 pTmpArray = pArray->u.array.pMember[i]; 427 else 428 pTmpArray = pArray; 429 430 if (pTmpArray->u.array.rf_rebuilding) { 431 #ifdef DEBUG 432 sprintf(buf, "Rebuilding %dMB", (pTmpArray->u.array.RebuildSectors>>11)); 433 #else 434 sprintf(buf, "Rebuilding %d%%", (pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)); 435 #endif 436 sStatus = buf; 437 } 438 else if (pTmpArray->u.array.rf_verifying) { 439 sprintf(buf, "Verifying %d%%", (pTmpArray->u.array.RebuildSectors>>11)*100/((pTmpArray->VDeviceCapacity/(pTmpArray->u.array.bArnMember-1))>>11)); 440 sStatus = buf; 441 } 442 else if (pTmpArray->u.array.rf_need_rebuild) 443 sStatus = "Critical"; 444 else if (pTmpArray->u.array.rf_broken) 445 sStatus = "Critical"; 446 447 if(pTmpArray == pArray) goto out; 448 } 449 else 450 goto out; 451 } 452 out: 453 if (!sStatus) sStatus = "Normal"; 454 hpt_copy_info(pinfo, "%2d %11s %-20s %5dMB %-16s", nld, sType, pArray->u.array.ArrayName, pArray->VDeviceCapacity>>11, sStatus); 455 } 456 #endif 457 458 static int hpt_get_info(IAL_ADAPTER_T *pAdapter, HPT_GET_INFO *pinfo) 459 { 460 PVBus _vbus_p = &pAdapter->VBus; 461 struct cam_periph *periph = NULL; 462 UINT channel,j,i; 463 PVDevice pVDev; 464 465 #ifndef FOR_DEMO 466 if (pAdapter->beeping) { 467 intrmask_t oldspl = lock_driver(); 468 pAdapter->beeping = 0; 469 BeepOff(pAdapter->mvSataAdapter.adapterIoBaseAddress); 470 unlock_driver(oldspl); 471 } 472 #endif 473 474 hpt_copy_info(pinfo, "Controller #%d:\n\n", pAdapter->mvSataAdapter.adapterId); 475 476 hpt_copy_info(pinfo, "Physical device list\n"); 477 hpt_copy_info(pinfo, "Channel Model Capacity Status Array\n"); 478 hpt_copy_info(pinfo, "-------------------------------------------------------------------\n"); 479 480 for (channel = 0; channel < MV_SATA_CHANNELS_NUM; channel++) 481 { 482 pVDev = &(pAdapter->VDevices[channel]); 483 if(pVDev->u.disk.df_on_line) 484 hpt_copy_disk_info(pinfo, pVDev, channel); 485 } 486 487 hpt_copy_info(pinfo, "\nLogical device list\n"); 488 hpt_copy_info(pinfo, "No. Type Name Capacity Status OsDisk\n"); 489 hpt_copy_info(pinfo, "--------------------------------------------------------------------------\n"); 490 491 j=1; 492 for(i = 0; i < MAX_VDEVICE_PER_VBUS; i++){ 493 pVDev = _vbus_p->pVDevice[i]; 494 if(pVDev){ 495 j=i+1; 496 #ifdef SUPPORT_ARRAY 497 if (mIsArray(pVDev)) 498 { 499 is_array: 500 hpt_copy_array_info(pinfo, j, pVDev); 501 } 502 else 503 #endif 504 { 505 char name[32]; 506 /* it may be add to an array after driver loaded, check it */ 507 #ifdef SUPPORT_ARRAY 508 if (pVDev->pParent) 509 /* in this case, pVDev can only be a RAID 1 source disk. */ 510 if (pVDev->pParent->VDeviceType==VD_RAID_1 && pVDev==pVDev->pParent->u.array.pMember[0]) 511 goto is_array; 512 #endif 513 get_disk_name(name, &pVDev->u.disk); 514 515 hpt_copy_info(pinfo, "%2d %s %s %5dMB %-16s", 516 j, "Single disk", name, pVDev->VDeviceCapacity>>11, 517 /* gmm 2001-6-19: Check if pDev has been added to an array. */ 518 ((pVDev->pParent) ? "Unavailable" : "Normal")); 519 } 520 periph = hpt_get_periph(pAdapter->mvSataAdapter.adapterId, i); 521 if (periph == NULL) 522 hpt_copy_info(pinfo," %s\n","not registered"); 523 else 524 hpt_copy_info(pinfo," %s%d\n", periph->periph_name, periph->unit_number); 525 } 526 } 527 return 0; 528 } 529 530 static inline int hpt_proc_in(FORMAL_HANDLER_ARGS, int *len) 531 { 532 int i, error=0; 533 534 *len = 0; 535 if ((req->newlen - req->newidx) >= sizeof(hptproc_buffer)) { 536 error = EINVAL; 537 } else { 538 i = (req->newlen - req->newidx); 539 error = SYSCTL_IN(req, hptproc_buffer, i); 540 if (!error) 541 *len = i; 542 (hptproc_buffer)[i] = '\0'; 543 } 544 return (error); 545 } 546 547 static int hpt_status(FORMAL_HANDLER_ARGS) 548 { 549 int length, error=0, retval=0; 550 IAL_ADAPTER_T *pAdapter; 551 552 error = hpt_proc_in(REAL_HANDLER_ARGS, &length); 553 554 if (req->newptr != NULL) 555 { 556 if (error || length == 0) 557 { 558 KdPrint(("error!\n")); 559 retval = EINVAL; 560 goto out; 561 } 562 563 if (hpt_set_info(length) >= 0) 564 retval = 0; 565 else 566 retval = EINVAL; 567 goto out; 568 } 569 570 hpt_copy_info(req, "%s Version %s\n", DRIVER_NAME, DRIVER_VERSION); 571 for (pAdapter=gIal_Adapter; pAdapter; pAdapter=pAdapter->next) { 572 if (hpt_get_info(pAdapter, req) < 0) { 573 retval = EINVAL; 574 break; 575 } 576 } 577 578 hpt_copy_info(req, NULL); 579 goto out; 580 581 out: 582 return (retval); 583 } 584 585 586 #define xhptregister_node(name) hptregister_node(name) 587 588 #if (__FreeBSD_version < 500043) 589 #define hptregister_node(name) \ 590 SYSCTL_NODE(, OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node") \ 591 SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \ 592 NULL, 0, hpt_status, "A", "Get/Set " #name " state") 593 #else 594 #define hptregister_node(name) \ 595 SYSCTL_NODE(, OID_AUTO, name, CTLFLAG_RW, 0, "Get/Set " #name " state root node"); \ 596 SYSCTL_OID(_ ## name, OID_AUTO, status, CTLTYPE_STRING|CTLFLAG_RW, \ 597 NULL, 0, hpt_status, "A", "Get/Set " #name " state"); 598 #endif 599 600 xhptregister_node(PROC_DIR_NAME); 601