mptsas_raid.c revision 9907:98086c85a8f7
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27/* 28 * Copyright (c) 2000 to 2009, LSI Corporation. 29 * All rights reserved. 30 * 31 * Redistribution and use in source and binary forms of all code within 32 * this file that is exclusively owned by LSI, with or without 33 * modification, is permitted provided that, in addition to the CDDL 1.0 34 * License requirements, the following conditions are met: 35 * 36 * Neither the name of the author nor the names of its contributors may be 37 * used to endorse or promote products derived from this software without 38 * specific prior written permission. 39 * 40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 43 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 44 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 46 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 47 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 48 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 51 * DAMAGE. 52 */ 53 54/* 55 * mptsas_raid - This file contains all the RAID related functions for the 56 * MPT interface. 57 */ 58 59#if defined(lint) || defined(DEBUG) 60#define MPTSAS_DEBUG 61#endif 62 63#define MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX 2 64 65/* 66 * standard header files 67 */ 68#include <sys/note.h> 69#include <sys/scsi/scsi.h> 70#include <sys/byteorder.h> 71#include <sys/raidioctl.h> 72 73#pragma pack(1) 74 75#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h> 76#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h> 77#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h> 78#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h> 79#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h> 80 81#pragma pack() 82 83/* 84 * private header files. 85 */ 86#include <sys/scsi/adapters/mpt_sas/mptsas_var.h> 87 88static int mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol); 89 90extern int mptsas_check_dma_handle(ddi_dma_handle_t handle); 91extern int mptsas_check_acc_handle(ddi_acc_handle_t handle); 92extern mptsas_target_t *mptsas_tgt_alloc(mptsas_hash_table_t *, uint16_t, 93 uint64_t, uint32_t, uint8_t, uint8_t); 94 95static int 96mptsas_raidconf_page_0_cb(mptsas_t *mpt, caddr_t page_memp, 97 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo, 98 va_list ap) 99{ 100#ifndef __lock_lint 101 _NOTE(ARGUNUSED(ap)) 102#endif 103 pMpi2RaidConfigurationPage0_t raidconfig_page0; 104 pMpi2RaidConfig0ConfigElement_t element; 105 uint32_t *confignum; 106 int rval = DDI_SUCCESS, i; 107 uint8_t numelements, vol, disk; 108 uint16_t elementtype, voldevhandle; 109 uint16_t etype_vol, etype_pd, etype_hs; 110 uint16_t etype_oce; 111 mptsas_slots_t *slots = mpt->m_active; 112 m_raidconfig_t *raidconfig; 113 uint64_t raidwwn; 114 uint32_t native; 115 mptsas_target_t *ptgt; 116 uint32_t configindex; 117 118 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) { 119 return (DDI_FAILURE); 120 } 121 122 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) { 123 mptsas_log(mpt, CE_WARN, "mptsas_get_raid_conf_page0 " 124 "config: IOCStatus=0x%x, IOCLogInfo=0x%x", 125 iocstatus, iocloginfo); 126 rval = DDI_FAILURE; 127 return (rval); 128 } 129 confignum = va_arg(ap, uint32_t *); 130 configindex = va_arg(ap, uint32_t); 131 raidconfig_page0 = (pMpi2RaidConfigurationPage0_t)page_memp; 132 /* 133 * Get all RAID configurations. 134 */ 135 etype_vol = MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT; 136 etype_pd = MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT; 137 etype_hs = MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT; 138 etype_oce = MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT; 139 /* 140 * Set up page address for next time through. 141 */ 142 *confignum = ddi_get8(accessp, 143 &raidconfig_page0->ConfigNum); 144 145 /* 146 * Point to the right config in the structure. 147 * Increment the number of valid RAID configs. 148 */ 149 raidconfig = &slots->m_raidconfig[configindex]; 150 slots->m_num_raid_configs++; 151 152 /* 153 * Set the native flag if this is not a foreign 154 * configuration. 155 */ 156 native = ddi_get32(accessp, &raidconfig_page0->Flags); 157 if (native & MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG) { 158 native = FALSE; 159 } else { 160 native = TRUE; 161 } 162 raidconfig->m_native = (uint8_t)native; 163 164 /* 165 * Get volume information for the volumes in the 166 * config. 167 */ 168 numelements = ddi_get8(accessp, &raidconfig_page0->NumElements); 169 vol = 0; 170 disk = 0; 171 element = (pMpi2RaidConfig0ConfigElement_t) 172 &raidconfig_page0->ConfigElement; 173 174 for (i = 0; i < numelements; i++, element++) { 175 /* 176 * Get the element type. Could be Volume, 177 * PhysDisk, Hot Spare, or Online Capacity 178 * Expansion PhysDisk. 179 */ 180 elementtype = ddi_get16(accessp, &element->ElementFlags); 181 elementtype &= MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE; 182 183 /* 184 * For volumes, get the RAID settings and the 185 * WWID. 186 */ 187 if (elementtype == etype_vol) { 188 voldevhandle = ddi_get16(accessp, 189 &element->VolDevHandle); 190 raidconfig->m_raidvol[vol].m_israid = 1; 191 raidconfig->m_raidvol[vol]. 192 m_raidhandle = voldevhandle; 193 /* 194 * Get the settings for the raid 195 * volume. This includes the 196 * DevHandles for the disks making up 197 * the raid volume. 198 */ 199 if (mptsas_get_raid_settings(mpt, 200 &raidconfig->m_raidvol[vol])) 201 continue; 202 203 /* 204 * Get the WWID of the RAID volume for 205 * SAS HBA 206 */ 207 if (mptsas_get_raid_wwid(mpt, 208 &raidconfig->m_raidvol[vol])) 209 continue; 210 211 raidwwn = raidconfig->m_raidvol[vol]. 212 m_raidwwid; 213 214 /* 215 * RAID uses phymask of 0. 216 */ 217 ptgt = mptsas_tgt_alloc(&slots->m_tgttbl, 218 voldevhandle, raidwwn, 0, 0, 0); 219 220 raidconfig->m_raidvol[vol].m_raidtgt = 221 ptgt; 222 223 /* 224 * Increment volume index within this 225 * raid config. 226 */ 227 vol++; 228 } else if ((elementtype == etype_pd) || 229 (elementtype == etype_hs) || 230 (elementtype == etype_oce)) { 231 /* 232 * For all other element types, put 233 * their DevHandles in the phys disk 234 * list of the config. These are all 235 * some variation of a Phys Disk and 236 * this list is used to keep these 237 * disks from going online. 238 */ 239 raidconfig->m_physdisk_devhdl[disk] = ddi_get16(accessp, 240 &element->PhysDiskDevHandle); 241 242 /* 243 * Increment disk index within this 244 * raid config. 245 */ 246 disk++; 247 } 248 } 249 250 return (rval); 251} 252 253int 254mptsas_get_raid_info(mptsas_t *mpt) 255{ 256 int rval = DDI_SUCCESS; 257 uint32_t confignum, pageaddress; 258 uint8_t configindex; 259 mptsas_slots_t *slots = mpt->m_active; 260 261 ASSERT(mutex_owned(&mpt->m_mutex)); 262 263 /* 264 * Clear all RAID info before starting. 265 */ 266 bzero(slots->m_raidconfig, sizeof (slots->m_raidconfig)); 267 slots->m_num_raid_configs = 0; 268 269 configindex = 0; 270 confignum = 0xff; 271 pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM | confignum; 272 while (rval == DDI_SUCCESS) { 273 /* 274 * Get the header and config page. reply contains the reply 275 * frame, which holds status info for the request. 276 */ 277 rval = mptsas_access_config_page(mpt, 278 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, 279 MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0, pageaddress, 280 mptsas_raidconf_page_0_cb, &confignum, configindex); 281 configindex++; 282 pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM | 283 confignum; 284 } 285 286 return (rval); 287} 288 289static int 290mptsas_raidvol_page_0_cb(mptsas_t *mpt, caddr_t page_memp, 291 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo, 292 va_list ap) 293{ 294#ifndef __lock_lint 295 _NOTE(ARGUNUSED(ap)) 296#endif 297 pMpi2RaidVolPage0_t raidpage; 298 int rval = DDI_SUCCESS, i; 299 mptsas_raidvol_t *raidvol; 300 uint8_t numdisks, volstate, voltype, physdisknum; 301 uint32_t volsetting; 302 uint32_t statusflags, resync_flag; 303 304 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) 305 return (DDI_FAILURE); 306 307 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) { 308 mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page0_cb " 309 "config: IOCStatus=0x%x, IOCLogInfo=0x%x", 310 iocstatus, iocloginfo); 311 rval = DDI_FAILURE; 312 return (rval); 313 } 314 315 raidvol = va_arg(ap, mptsas_raidvol_t *); 316 317 raidpage = (pMpi2RaidVolPage0_t)page_memp; 318 volstate = ddi_get8(accessp, &raidpage->VolumeState); 319 volsetting = ddi_get32(accessp, 320 (uint32_t *)(void *)&raidpage->VolumeSettings); 321 statusflags = ddi_get32(accessp, &raidpage->VolumeStatusFlags); 322 voltype = ddi_get8(accessp, &raidpage->VolumeType); 323 324 raidvol->m_state = volstate; 325 raidvol->m_statusflags = statusflags; 326 /* 327 * Volume size is not used right now. Set to 0. 328 */ 329 raidvol->m_raidsize = 0; 330 raidvol->m_settings = volsetting; 331 raidvol->m_raidlevel = voltype; 332 333 if (statusflags & MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED) { 334 mptsas_log(mpt, CE_NOTE, "?Volume %d is quiesced\n", 335 raidvol->m_raidhandle); 336 } 337 338 if (statusflags & 339 MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) { 340 mptsas_log(mpt, CE_NOTE, "?Volume %d is resyncing\n", 341 raidvol->m_raidhandle); 342 } 343 344 resync_flag = MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS; 345 switch (volstate) { 346 case MPI2_RAID_VOL_STATE_OPTIMAL: 347 mptsas_log(mpt, CE_NOTE, "?Volume %d is " 348 "optimal\n", raidvol->m_raidhandle); 349 break; 350 case MPI2_RAID_VOL_STATE_DEGRADED: 351 if ((statusflags & resync_flag) == 0) { 352 mptsas_log(mpt, CE_WARN, "Volume %d " 353 "is degraded\n", 354 raidvol->m_raidhandle); 355 } 356 break; 357 case MPI2_RAID_VOL_STATE_FAILED: 358 mptsas_log(mpt, CE_WARN, "Volume %d is " 359 "failed\n", raidvol->m_raidhandle); 360 break; 361 case MPI2_RAID_VOL_STATE_MISSING: 362 mptsas_log(mpt, CE_WARN, "Volume %d is " 363 "missing\n", raidvol->m_raidhandle); 364 break; 365 default: 366 break; 367 } 368 numdisks = raidpage->NumPhysDisks; 369 raidvol->m_ndisks = numdisks; 370 for (i = 0; i < numdisks; i++) { 371 physdisknum = raidpage->PhysDisk[i].PhysDiskNum; 372 raidvol->m_disknum[i] = physdisknum; 373 if (mptsas_get_physdisk_settings(mpt, raidvol, 374 physdisknum)) 375 break; 376 } 377 return (rval); 378} 379 380int 381mptsas_get_raid_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol) 382{ 383 int rval = DDI_SUCCESS; 384 uint32_t page_address; 385 386 ASSERT(mutex_owned(&mpt->m_mutex)); 387 388 /* 389 * Get the header and config page. reply contains the reply frame, 390 * which holds status info for the request. 391 */ 392 page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK & 393 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle; 394 rval = mptsas_access_config_page(mpt, 395 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, 396 MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0, page_address, 397 mptsas_raidvol_page_0_cb, raidvol); 398 399 return (rval); 400} 401 402static int 403mptsas_raidvol_page_1_cb(mptsas_t *mpt, caddr_t page_memp, 404 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo, 405 va_list ap) 406{ 407#ifndef __lock_lint 408 _NOTE(ARGUNUSED(ap)) 409#endif 410 pMpi2RaidVolPage1_t raidpage; 411 int rval = DDI_SUCCESS, i; 412 uint8_t *sas_addr = NULL; 413 uint8_t tmp_sas_wwn[SAS_WWN_BYTE_SIZE]; 414 uint64_t *sas_wwn; 415 416 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) { 417 mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page_1_cb " 418 "config: IOCStatus=0x%x, IOCLogInfo=0x%x", 419 iocstatus, iocloginfo); 420 rval = DDI_FAILURE; 421 return (rval); 422 } 423 sas_wwn = va_arg(ap, uint64_t *); 424 425 raidpage = (pMpi2RaidVolPage1_t)page_memp; 426 sas_addr = (uint8_t *)(&raidpage->WWID); 427 for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) { 428 tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i); 429 } 430 bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE); 431 *sas_wwn = LE_64(*sas_wwn); 432 return (rval); 433} 434 435static int 436mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol) 437{ 438 int rval = DDI_SUCCESS; 439 uint32_t page_address; 440 uint64_t sas_wwn; 441 442 ASSERT(mutex_owned(&mpt->m_mutex)); 443 444 /* 445 * Get the header and config page. reply contains the reply frame, 446 * which holds status info for the request. 447 */ 448 page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK & 449 MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle; 450 rval = mptsas_access_config_page(mpt, 451 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, 452 MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1, page_address, 453 mptsas_raidvol_page_1_cb, &sas_wwn); 454 455 /* 456 * Get the required information from the page. 457 */ 458 if (rval == DDI_SUCCESS) { 459 460 /* 461 * replace top nibble of WWID of RAID to '3' for OBP 462 */ 463 sas_wwn = MPTSAS_RAID_WWID(sas_wwn); 464 raidvol->m_raidwwid = sas_wwn; 465 } 466 467done: 468 return (rval); 469} 470 471static int 472mptsas_raidphydsk_page_0_cb(mptsas_t *mpt, caddr_t page_memp, 473 ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo, 474 va_list ap) 475{ 476#ifndef __lock_lint 477 _NOTE(ARGUNUSED(ap)) 478#endif 479 pMpi2RaidPhysDiskPage0_t diskpage; 480 int rval = DDI_SUCCESS; 481 uint16_t *devhdl; 482 uint8_t *state; 483 484 if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) 485 return (DDI_FAILURE); 486 487 if (iocstatus != MPI2_IOCSTATUS_SUCCESS) { 488 mptsas_log(mpt, CE_WARN, "mptsas_raidphydsk_page0_cb " 489 "config: IOCStatus=0x%x, IOCLogInfo=0x%x", 490 iocstatus, iocloginfo); 491 rval = DDI_FAILURE; 492 return (rval); 493 } 494 devhdl = va_arg(ap, uint16_t *); 495 state = va_arg(ap, uint8_t *); 496 diskpage = (pMpi2RaidPhysDiskPage0_t)page_memp; 497 *devhdl = ddi_get16(accessp, &diskpage->DevHandle); 498 *state = ddi_get8(accessp, &diskpage->PhysDiskState); 499 return (rval); 500} 501 502int 503mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol, 504 uint8_t physdisknum) 505{ 506 int rval = DDI_SUCCESS, i; 507 uint8_t state; 508 uint16_t devhdl; 509 uint32_t page_address; 510 511 ASSERT(mutex_owned(&mpt->m_mutex)); 512 513 /* 514 * Get the header and config page. reply contains the reply frame, 515 * which holds status info for the request. 516 */ 517 page_address = (MPI2_PHYSDISK_PGAD_FORM_MASK & 518 MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM) | physdisknum; 519 rval = mptsas_access_config_page(mpt, 520 MPI2_CONFIG_ACTION_PAGE_READ_CURRENT, 521 MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, page_address, 522 mptsas_raidphydsk_page_0_cb, &devhdl, &state); 523 524 /* 525 * Get the required information from the page. 526 */ 527 if (rval == DDI_SUCCESS) { 528 for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) { 529 /* find the correct position in the arrays */ 530 if (raidvol->m_disknum[i] == physdisknum) 531 break; 532 } 533 raidvol->m_devhdl[i] = devhdl; 534 535 switch (state) { 536 case MPI2_RAID_PD_STATE_OFFLINE: 537 raidvol->m_diskstatus[i] = 538 RAID_DISKSTATUS_FAILED; 539 break; 540 541 case MPI2_RAID_PD_STATE_HOT_SPARE: 542 case MPI2_RAID_PD_STATE_NOT_CONFIGURED: 543 case MPI2_RAID_PD_STATE_NOT_COMPATIBLE: 544 break; 545 546 case MPI2_RAID_PD_STATE_DEGRADED: 547 case MPI2_RAID_PD_STATE_OPTIMAL: 548 case MPI2_RAID_PD_STATE_REBUILDING: 549 case MPI2_RAID_PD_STATE_ONLINE: 550 default: 551 raidvol->m_diskstatus[i] = 552 RAID_DISKSTATUS_GOOD; 553 break; 554 } 555 } 556 557 return (rval); 558} 559 560int 561mptsas_delete_volume(mptsas_t *mpt, uint16_t volid) 562{ 563 int config, i, vol = (-1); 564 mptsas_slots_t *slots = mpt->m_active; 565 566 for (config = 0; config < slots->m_num_raid_configs; config++) { 567 for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) { 568 if (slots->m_raidconfig[config].m_raidvol[i]. 569 m_raidhandle == volid) { 570 vol = i; 571 break; 572 } 573 } 574 } 575 576 if (vol < 0) { 577 mptsas_log(mpt, CE_WARN, "raid doesn't exist at specified " 578 "target."); 579 return (-1); 580 } 581 582 slots->m_raidconfig[config].m_raidvol[vol].m_israid = 0; 583 slots->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0; 584 for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) { 585 slots->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0; 586 slots->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0; 587 } 588 589 return (0); 590} 591