diff options
Diffstat (limited to 'drivers/message/fusion/mptsas.c')
| -rw-r--r-- | drivers/message/fusion/mptsas.c | 818 |
1 files changed, 641 insertions, 177 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index 2512d0e6155e..010d4a39269b 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
| @@ -104,6 +104,13 @@ struct mptsas_hotplug_event { | |||
| 104 | u16 handle; | 104 | u16 handle; |
| 105 | u16 parent_handle; | 105 | u16 parent_handle; |
| 106 | u8 phy_id; | 106 | u8 phy_id; |
| 107 | u8 phys_disk_num; | ||
| 108 | u8 phys_disk_num_valid; | ||
| 109 | }; | ||
| 110 | |||
| 111 | struct mptsas_discovery_event { | ||
| 112 | struct work_struct work; | ||
| 113 | MPT_ADAPTER *ioc; | ||
| 107 | }; | 114 | }; |
| 108 | 115 | ||
| 109 | /* | 116 | /* |
| @@ -117,6 +124,8 @@ struct mptsas_hotplug_event { | |||
| 117 | struct mptsas_devinfo { | 124 | struct mptsas_devinfo { |
| 118 | u16 handle; /* unique id to address this device */ | 125 | u16 handle; /* unique id to address this device */ |
| 119 | u16 handle_parent; /* unique id to address parent device */ | 126 | u16 handle_parent; /* unique id to address parent device */ |
| 127 | u16 handle_enclosure; /* enclosure identifier of the enclosure */ | ||
| 128 | u16 slot; /* physical slot in enclosure */ | ||
| 120 | u8 phy_id; /* phy number of parent device */ | 129 | u8 phy_id; /* phy number of parent device */ |
| 121 | u8 port_id; /* sas physical port this device | 130 | u8 port_id; /* sas physical port this device |
| 122 | is assoc'd with */ | 131 | is assoc'd with */ |
| @@ -137,6 +146,7 @@ struct mptsas_phyinfo { | |||
| 137 | struct mptsas_devinfo attached; /* point to attached device info */ | 146 | struct mptsas_devinfo attached; /* point to attached device info */ |
| 138 | struct sas_phy *phy; | 147 | struct sas_phy *phy; |
| 139 | struct sas_rphy *rphy; | 148 | struct sas_rphy *rphy; |
| 149 | struct scsi_target *starget; | ||
| 140 | }; | 150 | }; |
| 141 | 151 | ||
| 142 | struct mptsas_portinfo { | 152 | struct mptsas_portinfo { |
| @@ -146,6 +156,17 @@ struct mptsas_portinfo { | |||
| 146 | struct mptsas_phyinfo *phy_info; | 156 | struct mptsas_phyinfo *phy_info; |
| 147 | }; | 157 | }; |
| 148 | 158 | ||
| 159 | struct mptsas_enclosure { | ||
| 160 | u64 enclosure_logical_id; /* The WWN for the enclosure */ | ||
| 161 | u16 enclosure_handle; /* unique id to address this */ | ||
| 162 | u16 flags; /* details enclosure management */ | ||
| 163 | u16 num_slot; /* num slots */ | ||
| 164 | u16 start_slot; /* first slot */ | ||
| 165 | u8 start_id; /* starting logical target id */ | ||
| 166 | u8 start_channel; /* starting logical channel id */ | ||
| 167 | u8 sep_id; /* SEP device logical target id */ | ||
| 168 | u8 sep_channel; /* SEP channel logical channel id */ | ||
| 169 | }; | ||
| 149 | 170 | ||
| 150 | #ifdef SASDEBUG | 171 | #ifdef SASDEBUG |
| 151 | static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) | 172 | static void mptsas_print_phy_data(MPI_SAS_IO_UNIT0_PHY_DATA *phy_data) |
| @@ -205,6 +226,7 @@ static void mptsas_print_device_pg0(SasDevicePage0_t *pg0) | |||
| 205 | 226 | ||
| 206 | printk("---- SAS DEVICE PAGE 0 ---------\n"); | 227 | printk("---- SAS DEVICE PAGE 0 ---------\n"); |
| 207 | printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)); | 228 | printk("Handle=0x%X\n" ,le16_to_cpu(pg0->DevHandle)); |
| 229 | printk("Parent Handle=0x%X\n" ,le16_to_cpu(pg0->ParentDevHandle)); | ||
| 208 | printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); | 230 | printk("Enclosure Handle=0x%X\n", le16_to_cpu(pg0->EnclosureHandle)); |
| 209 | printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); | 231 | printk("Slot=0x%X\n", le16_to_cpu(pg0->Slot)); |
| 210 | printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); | 232 | printk("SAS Address=0x%llX\n", le64_to_cpu(sas_address)); |
| @@ -243,6 +265,111 @@ static void mptsas_print_expander_pg1(SasExpanderPage1_t *pg1) | |||
| 243 | #define mptsas_print_expander_pg1(pg1) do { } while (0) | 265 | #define mptsas_print_expander_pg1(pg1) do { } while (0) |
| 244 | #endif | 266 | #endif |
| 245 | 267 | ||
| 268 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) | ||
| 269 | { | ||
| 270 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
| 271 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
| 272 | } | ||
| 273 | |||
| 274 | static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy) | ||
| 275 | { | ||
| 276 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent); | ||
| 277 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
| 278 | } | ||
| 279 | |||
| 280 | /* | ||
| 281 | * mptsas_find_portinfo_by_handle | ||
| 282 | * | ||
| 283 | * This function should be called with the sas_topology_mutex already held | ||
| 284 | */ | ||
| 285 | static struct mptsas_portinfo * | ||
| 286 | mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle) | ||
| 287 | { | ||
| 288 | struct mptsas_portinfo *port_info, *rc=NULL; | ||
| 289 | int i; | ||
| 290 | |||
| 291 | list_for_each_entry(port_info, &ioc->sas_topology, list) | ||
| 292 | for (i = 0; i < port_info->num_phys; i++) | ||
| 293 | if (port_info->phy_info[i].identify.handle == handle) { | ||
| 294 | rc = port_info; | ||
| 295 | goto out; | ||
| 296 | } | ||
| 297 | out: | ||
| 298 | return rc; | ||
| 299 | } | ||
| 300 | |||
| 301 | static int | ||
| 302 | mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure, | ||
| 303 | u32 form, u32 form_specific) | ||
| 304 | { | ||
| 305 | ConfigExtendedPageHeader_t hdr; | ||
| 306 | CONFIGPARMS cfg; | ||
| 307 | SasEnclosurePage0_t *buffer; | ||
| 308 | dma_addr_t dma_handle; | ||
| 309 | int error; | ||
| 310 | __le64 le_identifier; | ||
| 311 | |||
| 312 | memset(&hdr, 0, sizeof(hdr)); | ||
| 313 | hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION; | ||
| 314 | hdr.PageNumber = 0; | ||
| 315 | hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; | ||
| 316 | hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE; | ||
| 317 | |||
| 318 | cfg.cfghdr.ehdr = &hdr; | ||
| 319 | cfg.physAddr = -1; | ||
| 320 | cfg.pageAddr = form + form_specific; | ||
| 321 | cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; | ||
| 322 | cfg.dir = 0; /* read */ | ||
| 323 | cfg.timeout = 10; | ||
| 324 | |||
| 325 | error = mpt_config(ioc, &cfg); | ||
| 326 | if (error) | ||
| 327 | goto out; | ||
| 328 | if (!hdr.ExtPageLength) { | ||
| 329 | error = -ENXIO; | ||
| 330 | goto out; | ||
| 331 | } | ||
| 332 | |||
| 333 | buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | ||
| 334 | &dma_handle); | ||
| 335 | if (!buffer) { | ||
| 336 | error = -ENOMEM; | ||
| 337 | goto out; | ||
| 338 | } | ||
| 339 | |||
| 340 | cfg.physAddr = dma_handle; | ||
| 341 | cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; | ||
| 342 | |||
| 343 | error = mpt_config(ioc, &cfg); | ||
| 344 | if (error) | ||
| 345 | goto out_free_consistent; | ||
| 346 | |||
| 347 | /* save config data */ | ||
| 348 | memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64)); | ||
| 349 | enclosure->enclosure_logical_id = le64_to_cpu(le_identifier); | ||
| 350 | enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle); | ||
| 351 | enclosure->flags = le16_to_cpu(buffer->Flags); | ||
| 352 | enclosure->num_slot = le16_to_cpu(buffer->NumSlots); | ||
| 353 | enclosure->start_slot = le16_to_cpu(buffer->StartSlot); | ||
| 354 | enclosure->start_id = buffer->StartTargetID; | ||
| 355 | enclosure->start_channel = buffer->StartBus; | ||
| 356 | enclosure->sep_id = buffer->SEPTargetID; | ||
| 357 | enclosure->sep_channel = buffer->SEPBus; | ||
| 358 | |||
| 359 | out_free_consistent: | ||
| 360 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | ||
| 361 | buffer, dma_handle); | ||
| 362 | out: | ||
| 363 | return error; | ||
| 364 | } | ||
| 365 | |||
| 366 | static int | ||
| 367 | mptsas_slave_configure(struct scsi_device *sdev) | ||
| 368 | { | ||
| 369 | sas_read_port_mode_page(sdev); | ||
| 370 | |||
| 371 | return mptscsih_slave_configure(sdev); | ||
| 372 | } | ||
| 246 | 373 | ||
| 247 | /* | 374 | /* |
| 248 | * This is pretty ugly. We will be able to seriously clean it up | 375 | * This is pretty ugly. We will be able to seriously clean it up |
| @@ -259,6 +386,7 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
| 259 | VirtTarget *vtarget; | 386 | VirtTarget *vtarget; |
| 260 | VirtDevice *vdev; | 387 | VirtDevice *vdev; |
| 261 | struct scsi_target *starget; | 388 | struct scsi_target *starget; |
| 389 | u32 target_id; | ||
| 262 | int i; | 390 | int i; |
| 263 | 391 | ||
| 264 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); | 392 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); |
| @@ -267,10 +395,10 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
| 267 | hd->ioc->name, sizeof(VirtDevice)); | 395 | hd->ioc->name, sizeof(VirtDevice)); |
| 268 | return -ENOMEM; | 396 | return -ENOMEM; |
| 269 | } | 397 | } |
| 270 | vdev->ioc_id = hd->ioc->id; | ||
| 271 | sdev->hostdata = vdev; | 398 | sdev->hostdata = vdev; |
| 272 | starget = scsi_target(sdev); | 399 | starget = scsi_target(sdev); |
| 273 | vtarget = starget->hostdata; | 400 | vtarget = starget->hostdata; |
| 401 | vtarget->ioc_id = hd->ioc->id; | ||
| 274 | vdev->vtarget = vtarget; | 402 | vdev->vtarget = vtarget; |
| 275 | if (vtarget->num_luns == 0) { | 403 | if (vtarget->num_luns == 0) { |
| 276 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; | 404 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES|MPT_TARGET_FLAGS_VALID_INQUIRY; |
| @@ -281,8 +409,8 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
| 281 | RAID volumes placed beyond the last expected port. | 409 | RAID volumes placed beyond the last expected port. |
| 282 | */ | 410 | */ |
| 283 | if (sdev->channel == hd->ioc->num_ports) { | 411 | if (sdev->channel == hd->ioc->num_ports) { |
| 284 | vdev->target_id = sdev->id; | 412 | target_id = sdev->id; |
| 285 | vdev->bus_id = 0; | 413 | vtarget->bus_id = 0; |
| 286 | vdev->lun = 0; | 414 | vdev->lun = 0; |
| 287 | goto out; | 415 | goto out; |
| 288 | } | 416 | } |
| @@ -293,11 +421,21 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
| 293 | for (i = 0; i < p->num_phys; i++) { | 421 | for (i = 0; i < p->num_phys; i++) { |
| 294 | if (p->phy_info[i].attached.sas_address == | 422 | if (p->phy_info[i].attached.sas_address == |
| 295 | rphy->identify.sas_address) { | 423 | rphy->identify.sas_address) { |
| 296 | vdev->target_id = | 424 | target_id = p->phy_info[i].attached.id; |
| 297 | p->phy_info[i].attached.id; | 425 | vtarget->bus_id = p->phy_info[i].attached.channel; |
| 298 | vdev->bus_id = p->phy_info[i].attached.channel; | ||
| 299 | vdev->lun = sdev->lun; | 426 | vdev->lun = sdev->lun; |
| 300 | mutex_unlock(&hd->ioc->sas_topology_mutex); | 427 | p->phy_info[i].starget = sdev->sdev_target; |
| 428 | /* | ||
| 429 | * Exposing hidden disk (RAID) | ||
| 430 | */ | ||
| 431 | if (mptscsih_is_phys_disk(hd->ioc, target_id)) { | ||
| 432 | target_id = mptscsih_raid_id_to_num(hd, | ||
| 433 | target_id); | ||
| 434 | vdev->vtarget->tflags |= | ||
| 435 | MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
| 436 | sdev->no_uld_attach = 1; | ||
| 437 | } | ||
| 438 | mutex_unlock(&hd->ioc->sas_topology_mutex); | ||
| 301 | goto out; | 439 | goto out; |
| 302 | } | 440 | } |
| 303 | } | 441 | } |
| @@ -308,9 +446,7 @@ mptsas_slave_alloc(struct scsi_device *sdev) | |||
| 308 | return -ENXIO; | 446 | return -ENXIO; |
| 309 | 447 | ||
| 310 | out: | 448 | out: |
| 311 | vtarget->ioc_id = vdev->ioc_id; | 449 | vtarget->target_id = target_id; |
| 312 | vtarget->target_id = vdev->target_id; | ||
| 313 | vtarget->bus_id = vdev->bus_id; | ||
| 314 | vtarget->num_luns++; | 450 | vtarget->num_luns++; |
| 315 | return 0; | 451 | return 0; |
| 316 | } | 452 | } |
| @@ -320,41 +456,17 @@ mptsas_slave_destroy(struct scsi_device *sdev) | |||
| 320 | { | 456 | { |
| 321 | struct Scsi_Host *host = sdev->host; | 457 | struct Scsi_Host *host = sdev->host; |
| 322 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; | 458 | MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)host->hostdata; |
| 323 | struct sas_rphy *rphy; | ||
| 324 | struct mptsas_portinfo *p; | ||
| 325 | int i; | ||
| 326 | VirtDevice *vdev; | 459 | VirtDevice *vdev; |
| 327 | 460 | ||
| 328 | /* | 461 | /* |
| 329 | * Handle hotplug removal case. | ||
| 330 | * We need to clear out attached data structure. | ||
| 331 | */ | ||
| 332 | rphy = dev_to_rphy(sdev->sdev_target->dev.parent); | ||
| 333 | |||
| 334 | mutex_lock(&hd->ioc->sas_topology_mutex); | ||
| 335 | list_for_each_entry(p, &hd->ioc->sas_topology, list) { | ||
| 336 | for (i = 0; i < p->num_phys; i++) { | ||
| 337 | if (p->phy_info[i].attached.sas_address == | ||
| 338 | rphy->identify.sas_address) { | ||
| 339 | memset(&p->phy_info[i].attached, 0, | ||
| 340 | sizeof(struct mptsas_devinfo)); | ||
| 341 | p->phy_info[i].rphy = NULL; | ||
| 342 | goto out; | ||
| 343 | } | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | out: | ||
| 348 | mutex_unlock(&hd->ioc->sas_topology_mutex); | ||
| 349 | /* | ||
| 350 | * Issue target reset to flush firmware outstanding commands. | 462 | * Issue target reset to flush firmware outstanding commands. |
| 351 | */ | 463 | */ |
| 352 | vdev = sdev->hostdata; | 464 | vdev = sdev->hostdata; |
| 353 | if (vdev->configured_lun){ | 465 | if (vdev->configured_lun){ |
| 354 | if (mptscsih_TMHandler(hd, | 466 | if (mptscsih_TMHandler(hd, |
| 355 | MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, | 467 | MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, |
| 356 | vdev->bus_id, | 468 | vdev->vtarget->bus_id, |
| 357 | vdev->target_id, | 469 | vdev->vtarget->target_id, |
| 358 | 0, 0, 5 /* 5 second timeout */) | 470 | 0, 0, 5 /* 5 second timeout */) |
| 359 | < 0){ | 471 | < 0){ |
| 360 | 472 | ||
| @@ -364,7 +476,7 @@ mptsas_slave_destroy(struct scsi_device *sdev) | |||
| 364 | printk(MYIOC_s_WARN_FMT | 476 | printk(MYIOC_s_WARN_FMT |
| 365 | "Error processing TaskMgmt id=%d TARGET_RESET\n", | 477 | "Error processing TaskMgmt id=%d TARGET_RESET\n", |
| 366 | hd->ioc->name, | 478 | hd->ioc->name, |
| 367 | vdev->target_id); | 479 | vdev->vtarget->target_id); |
| 368 | 480 | ||
| 369 | hd->tmPending = 0; | 481 | hd->tmPending = 0; |
| 370 | hd->tmState = TM_STATE_NONE; | 482 | hd->tmState = TM_STATE_NONE; |
| @@ -382,7 +494,7 @@ static struct scsi_host_template mptsas_driver_template = { | |||
| 382 | .queuecommand = mptscsih_qcmd, | 494 | .queuecommand = mptscsih_qcmd, |
| 383 | .target_alloc = mptscsih_target_alloc, | 495 | .target_alloc = mptscsih_target_alloc, |
| 384 | .slave_alloc = mptsas_slave_alloc, | 496 | .slave_alloc = mptsas_slave_alloc, |
| 385 | .slave_configure = mptscsih_slave_configure, | 497 | .slave_configure = mptsas_slave_configure, |
| 386 | .target_destroy = mptscsih_target_destroy, | 498 | .target_destroy = mptscsih_target_destroy, |
| 387 | .slave_destroy = mptsas_slave_destroy, | 499 | .slave_destroy = mptsas_slave_destroy, |
| 388 | .change_queue_depth = mptscsih_change_queue_depth, | 500 | .change_queue_depth = mptscsih_change_queue_depth, |
| @@ -399,12 +511,6 @@ static struct scsi_host_template mptsas_driver_template = { | |||
| 399 | .use_clustering = ENABLE_CLUSTERING, | 511 | .use_clustering = ENABLE_CLUSTERING, |
| 400 | }; | 512 | }; |
| 401 | 513 | ||
| 402 | static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy) | ||
| 403 | { | ||
| 404 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
| 405 | return ((MPT_SCSI_HOST *)shost->hostdata)->ioc; | ||
| 406 | } | ||
| 407 | |||
| 408 | static int mptsas_get_linkerrors(struct sas_phy *phy) | 514 | static int mptsas_get_linkerrors(struct sas_phy *phy) |
| 409 | { | 515 | { |
| 410 | MPT_ADAPTER *ioc = phy_to_ioc(phy); | 516 | MPT_ADAPTER *ioc = phy_to_ioc(phy); |
| @@ -546,8 +652,67 @@ static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | |||
| 546 | return error; | 652 | return error; |
| 547 | } | 653 | } |
| 548 | 654 | ||
| 655 | static int | ||
| 656 | mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) | ||
| 657 | { | ||
| 658 | MPT_ADAPTER *ioc = rphy_to_ioc(rphy); | ||
| 659 | int i, error; | ||
| 660 | struct mptsas_portinfo *p; | ||
| 661 | struct mptsas_enclosure enclosure_info; | ||
| 662 | u64 enclosure_handle; | ||
| 663 | |||
| 664 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 665 | list_for_each_entry(p, &ioc->sas_topology, list) { | ||
| 666 | for (i = 0; i < p->num_phys; i++) { | ||
| 667 | if (p->phy_info[i].attached.sas_address == | ||
| 668 | rphy->identify.sas_address) { | ||
| 669 | enclosure_handle = p->phy_info[i]. | ||
| 670 | attached.handle_enclosure; | ||
| 671 | goto found_info; | ||
| 672 | } | ||
| 673 | } | ||
| 674 | } | ||
| 675 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 676 | return -ENXIO; | ||
| 677 | |||
| 678 | found_info: | ||
| 679 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 680 | memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure)); | ||
| 681 | error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info, | ||
| 682 | (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE << | ||
| 683 | MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle); | ||
| 684 | if (!error) | ||
| 685 | *identifier = enclosure_info.enclosure_logical_id; | ||
| 686 | return error; | ||
| 687 | } | ||
| 688 | |||
| 689 | static int | ||
| 690 | mptsas_get_bay_identifier(struct sas_rphy *rphy) | ||
| 691 | { | ||
| 692 | MPT_ADAPTER *ioc = rphy_to_ioc(rphy); | ||
| 693 | struct mptsas_portinfo *p; | ||
| 694 | int i, rc; | ||
| 695 | |||
| 696 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 697 | list_for_each_entry(p, &ioc->sas_topology, list) { | ||
| 698 | for (i = 0; i < p->num_phys; i++) { | ||
| 699 | if (p->phy_info[i].attached.sas_address == | ||
| 700 | rphy->identify.sas_address) { | ||
| 701 | rc = p->phy_info[i].attached.slot; | ||
| 702 | goto out; | ||
| 703 | } | ||
| 704 | } | ||
| 705 | } | ||
| 706 | rc = -ENXIO; | ||
| 707 | out: | ||
| 708 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 709 | return rc; | ||
| 710 | } | ||
| 711 | |||
| 549 | static struct sas_function_template mptsas_transport_functions = { | 712 | static struct sas_function_template mptsas_transport_functions = { |
| 550 | .get_linkerrors = mptsas_get_linkerrors, | 713 | .get_linkerrors = mptsas_get_linkerrors, |
| 714 | .get_enclosure_identifier = mptsas_get_enclosure_identifier, | ||
| 715 | .get_bay_identifier = mptsas_get_bay_identifier, | ||
| 551 | .phy_reset = mptsas_phy_reset, | 716 | .phy_reset = mptsas_phy_reset, |
| 552 | }; | 717 | }; |
| 553 | 718 | ||
| @@ -607,6 +772,9 @@ mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info) | |||
| 607 | goto out_free_consistent; | 772 | goto out_free_consistent; |
| 608 | } | 773 | } |
| 609 | 774 | ||
| 775 | if (port_info->num_phys) | ||
| 776 | port_info->handle = | ||
| 777 | le16_to_cpu(buffer->PhyData[0].ControllerDevHandle); | ||
| 610 | for (i = 0; i < port_info->num_phys; i++) { | 778 | for (i = 0; i < port_info->num_phys; i++) { |
| 611 | mptsas_print_phy_data(&buffer->PhyData[i]); | 779 | mptsas_print_phy_data(&buffer->PhyData[i]); |
| 612 | port_info->phy_info[i].phy_id = i; | 780 | port_info->phy_info[i].phy_id = i; |
| @@ -713,6 +881,7 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
| 713 | cfg.dir = 0; /* read */ | 881 | cfg.dir = 0; /* read */ |
| 714 | cfg.timeout = 10; | 882 | cfg.timeout = 10; |
| 715 | 883 | ||
| 884 | memset(device_info, 0, sizeof(struct mptsas_devinfo)); | ||
| 716 | error = mpt_config(ioc, &cfg); | 885 | error = mpt_config(ioc, &cfg); |
| 717 | if (error) | 886 | if (error) |
| 718 | goto out; | 887 | goto out; |
| @@ -739,6 +908,9 @@ mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info, | |||
| 739 | 908 | ||
| 740 | device_info->handle = le16_to_cpu(buffer->DevHandle); | 909 | device_info->handle = le16_to_cpu(buffer->DevHandle); |
| 741 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); | 910 | device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle); |
| 911 | device_info->handle_enclosure = | ||
| 912 | le16_to_cpu(buffer->EnclosureHandle); | ||
| 913 | device_info->slot = le16_to_cpu(buffer->Slot); | ||
| 742 | device_info->phy_id = buffer->PhyNum; | 914 | device_info->phy_id = buffer->PhyNum; |
| 743 | device_info->port_id = buffer->PhysicalPort; | 915 | device_info->port_id = buffer->PhysicalPort; |
| 744 | device_info->id = buffer->TargetID; | 916 | device_info->id = buffer->TargetID; |
| @@ -780,6 +952,7 @@ mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info, | |||
| 780 | cfg.dir = 0; /* read */ | 952 | cfg.dir = 0; /* read */ |
| 781 | cfg.timeout = 10; | 953 | cfg.timeout = 10; |
| 782 | 954 | ||
| 955 | memset(port_info, 0, sizeof(struct mptsas_portinfo)); | ||
| 783 | error = mpt_config(ioc, &cfg); | 956 | error = mpt_config(ioc, &cfg); |
| 784 | if (error) | 957 | if (error) |
| 785 | goto out; | 958 | goto out; |
| @@ -880,7 +1053,6 @@ mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, | |||
| 880 | phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); | 1053 | phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle); |
| 881 | phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); | 1054 | phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle); |
| 882 | 1055 | ||
| 883 | |||
| 884 | out_free_consistent: | 1056 | out_free_consistent: |
| 885 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, | 1057 | pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4, |
| 886 | buffer, dma_handle); | 1058 | buffer, dma_handle); |
| @@ -970,12 +1142,19 @@ mptsas_parse_device_info(struct sas_identify *identify, | |||
| 970 | static int mptsas_probe_one_phy(struct device *dev, | 1142 | static int mptsas_probe_one_phy(struct device *dev, |
| 971 | struct mptsas_phyinfo *phy_info, int index, int local) | 1143 | struct mptsas_phyinfo *phy_info, int index, int local) |
| 972 | { | 1144 | { |
| 1145 | MPT_ADAPTER *ioc; | ||
| 973 | struct sas_phy *phy; | 1146 | struct sas_phy *phy; |
| 974 | int error; | 1147 | int error; |
| 975 | 1148 | ||
| 976 | phy = sas_phy_alloc(dev, index); | 1149 | if (!dev) |
| 977 | if (!phy) | 1150 | return -ENODEV; |
| 978 | return -ENOMEM; | 1151 | |
| 1152 | if (!phy_info->phy) { | ||
| 1153 | phy = sas_phy_alloc(dev, index); | ||
| 1154 | if (!phy) | ||
| 1155 | return -ENOMEM; | ||
| 1156 | } else | ||
| 1157 | phy = phy_info->phy; | ||
| 979 | 1158 | ||
| 980 | phy->port_identifier = phy_info->port_id; | 1159 | phy->port_identifier = phy_info->port_id; |
| 981 | mptsas_parse_device_info(&phy->identify, &phy_info->identify); | 1160 | mptsas_parse_device_info(&phy->identify, &phy_info->identify); |
| @@ -1061,24 +1240,54 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 1061 | break; | 1240 | break; |
| 1062 | } | 1241 | } |
| 1063 | 1242 | ||
| 1064 | if (local) | 1243 | if (!phy_info->phy) { |
| 1065 | phy->local_attached = 1; | ||
| 1066 | 1244 | ||
| 1067 | error = sas_phy_add(phy); | 1245 | if (local) |
| 1068 | if (error) { | 1246 | phy->local_attached = 1; |
| 1069 | sas_phy_free(phy); | 1247 | |
| 1070 | return error; | 1248 | error = sas_phy_add(phy); |
| 1249 | if (error) { | ||
| 1250 | sas_phy_free(phy); | ||
| 1251 | return error; | ||
| 1252 | } | ||
| 1253 | phy_info->phy = phy; | ||
| 1071 | } | 1254 | } |
| 1072 | phy_info->phy = phy; | ||
| 1073 | 1255 | ||
| 1074 | if (phy_info->attached.handle) { | 1256 | if ((phy_info->attached.handle) && |
| 1257 | (!phy_info->rphy)) { | ||
| 1258 | |||
| 1075 | struct sas_rphy *rphy; | 1259 | struct sas_rphy *rphy; |
| 1260 | struct sas_identify identify; | ||
| 1261 | |||
| 1262 | ioc = phy_to_ioc(phy_info->phy); | ||
| 1076 | 1263 | ||
| 1077 | rphy = sas_rphy_alloc(phy); | 1264 | /* |
| 1265 | * Let the hotplug_work thread handle processing | ||
| 1266 | * the adding/removing of devices that occur | ||
| 1267 | * after start of day. | ||
| 1268 | */ | ||
| 1269 | if (ioc->sas_discovery_runtime && | ||
| 1270 | mptsas_is_end_device(&phy_info->attached)) | ||
| 1271 | return 0; | ||
| 1272 | |||
| 1273 | mptsas_parse_device_info(&identify, &phy_info->attached); | ||
| 1274 | switch (identify.device_type) { | ||
| 1275 | case SAS_END_DEVICE: | ||
| 1276 | rphy = sas_end_device_alloc(phy); | ||
| 1277 | break; | ||
| 1278 | case SAS_EDGE_EXPANDER_DEVICE: | ||
| 1279 | case SAS_FANOUT_EXPANDER_DEVICE: | ||
| 1280 | rphy = sas_expander_alloc(phy, identify.device_type); | ||
| 1281 | break; | ||
| 1282 | default: | ||
| 1283 | rphy = NULL; | ||
| 1284 | break; | ||
| 1285 | } | ||
| 1078 | if (!rphy) | 1286 | if (!rphy) |
| 1079 | return 0; /* non-fatal: an rphy can be added later */ | 1287 | return 0; /* non-fatal: an rphy can be added later */ |
| 1080 | 1288 | ||
| 1081 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); | 1289 | rphy->identify = identify; |
| 1290 | |||
| 1082 | error = sas_rphy_add(rphy); | 1291 | error = sas_rphy_add(rphy); |
| 1083 | if (error) { | 1292 | if (error) { |
| 1084 | sas_rphy_free(rphy); | 1293 | sas_rphy_free(rphy); |
| @@ -1092,24 +1301,37 @@ static int mptsas_probe_one_phy(struct device *dev, | |||
| 1092 | } | 1301 | } |
| 1093 | 1302 | ||
| 1094 | static int | 1303 | static int |
| 1095 | mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) | 1304 | mptsas_probe_hba_phys(MPT_ADAPTER *ioc) |
| 1096 | { | 1305 | { |
| 1097 | struct mptsas_portinfo *port_info; | 1306 | struct mptsas_portinfo *port_info, *hba; |
| 1098 | u32 handle = 0xFFFF; | 1307 | u32 handle = 0xFFFF; |
| 1099 | int error = -ENOMEM, i; | 1308 | int error = -ENOMEM, i; |
| 1100 | 1309 | ||
| 1101 | port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); | 1310 | hba = kzalloc(sizeof(*port_info), GFP_KERNEL); |
| 1102 | if (!port_info) | 1311 | if (! hba) |
| 1103 | goto out; | 1312 | goto out; |
| 1104 | 1313 | ||
| 1105 | error = mptsas_sas_io_unit_pg0(ioc, port_info); | 1314 | error = mptsas_sas_io_unit_pg0(ioc, hba); |
| 1106 | if (error) | 1315 | if (error) |
| 1107 | goto out_free_port_info; | 1316 | goto out_free_port_info; |
| 1108 | 1317 | ||
| 1109 | ioc->num_ports = port_info->num_phys; | ||
| 1110 | mutex_lock(&ioc->sas_topology_mutex); | 1318 | mutex_lock(&ioc->sas_topology_mutex); |
| 1111 | list_add_tail(&port_info->list, &ioc->sas_topology); | 1319 | port_info = mptsas_find_portinfo_by_handle(ioc, hba->handle); |
| 1320 | if (!port_info) { | ||
| 1321 | port_info = hba; | ||
| 1322 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
| 1323 | } else { | ||
| 1324 | port_info->handle = hba->handle; | ||
| 1325 | for (i = 0; i < hba->num_phys; i++) | ||
| 1326 | port_info->phy_info[i].negotiated_link_rate = | ||
| 1327 | hba->phy_info[i].negotiated_link_rate; | ||
| 1328 | if (hba->phy_info) | ||
| 1329 | kfree(hba->phy_info); | ||
| 1330 | kfree(hba); | ||
| 1331 | hba = NULL; | ||
| 1332 | } | ||
| 1112 | mutex_unlock(&ioc->sas_topology_mutex); | 1333 | mutex_unlock(&ioc->sas_topology_mutex); |
| 1334 | ioc->num_ports = port_info->num_phys; | ||
| 1113 | 1335 | ||
| 1114 | for (i = 0; i < port_info->num_phys; i++) { | 1336 | for (i = 0; i < port_info->num_phys; i++) { |
| 1115 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], | 1337 | mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i], |
| @@ -1132,38 +1354,49 @@ mptsas_probe_hba_phys(MPT_ADAPTER *ioc, int *index) | |||
| 1132 | } | 1354 | } |
| 1133 | 1355 | ||
| 1134 | mptsas_probe_one_phy(&ioc->sh->shost_gendev, | 1356 | mptsas_probe_one_phy(&ioc->sh->shost_gendev, |
| 1135 | &port_info->phy_info[i], *index, 1); | 1357 | &port_info->phy_info[i], ioc->sas_index, 1); |
| 1136 | (*index)++; | 1358 | ioc->sas_index++; |
| 1137 | } | 1359 | } |
| 1138 | 1360 | ||
| 1139 | return 0; | 1361 | return 0; |
| 1140 | 1362 | ||
| 1141 | out_free_port_info: | 1363 | out_free_port_info: |
| 1142 | kfree(port_info); | 1364 | if (hba) |
| 1365 | kfree(hba); | ||
| 1143 | out: | 1366 | out: |
| 1144 | return error; | 1367 | return error; |
| 1145 | } | 1368 | } |
| 1146 | 1369 | ||
| 1147 | static int | 1370 | static int |
| 1148 | mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | 1371 | mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle) |
| 1149 | { | 1372 | { |
| 1150 | struct mptsas_portinfo *port_info, *p; | 1373 | struct mptsas_portinfo *port_info, *p, *ex; |
| 1151 | int error = -ENOMEM, i, j; | 1374 | int error = -ENOMEM, i, j; |
| 1152 | 1375 | ||
| 1153 | port_info = kzalloc(sizeof(*port_info), GFP_KERNEL); | 1376 | ex = kzalloc(sizeof(*port_info), GFP_KERNEL); |
| 1154 | if (!port_info) | 1377 | if (!ex) |
| 1155 | goto out; | 1378 | goto out; |
| 1156 | 1379 | ||
| 1157 | error = mptsas_sas_expander_pg0(ioc, port_info, | 1380 | error = mptsas_sas_expander_pg0(ioc, ex, |
| 1158 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << | 1381 | (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE << |
| 1159 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); | 1382 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), *handle); |
| 1160 | if (error) | 1383 | if (error) |
| 1161 | goto out_free_port_info; | 1384 | goto out_free_port_info; |
| 1162 | 1385 | ||
| 1163 | *handle = port_info->handle; | 1386 | *handle = ex->handle; |
| 1164 | 1387 | ||
| 1165 | mutex_lock(&ioc->sas_topology_mutex); | 1388 | mutex_lock(&ioc->sas_topology_mutex); |
| 1166 | list_add_tail(&port_info->list, &ioc->sas_topology); | 1389 | port_info = mptsas_find_portinfo_by_handle(ioc, *handle); |
| 1390 | if (!port_info) { | ||
| 1391 | port_info = ex; | ||
| 1392 | list_add_tail(&port_info->list, &ioc->sas_topology); | ||
| 1393 | } else { | ||
| 1394 | port_info->handle = ex->handle; | ||
| 1395 | if (ex->phy_info) | ||
| 1396 | kfree(ex->phy_info); | ||
| 1397 | kfree(ex); | ||
| 1398 | ex = NULL; | ||
| 1399 | } | ||
| 1167 | mutex_unlock(&ioc->sas_topology_mutex); | 1400 | mutex_unlock(&ioc->sas_topology_mutex); |
| 1168 | 1401 | ||
| 1169 | for (i = 0; i < port_info->num_phys; i++) { | 1402 | for (i = 0; i < port_info->num_phys; i++) { |
| @@ -1189,6 +1422,8 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
| 1189 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 1422 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
| 1190 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 1423 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
| 1191 | port_info->phy_info[i].attached.handle); | 1424 | port_info->phy_info[i].attached.handle); |
| 1425 | port_info->phy_info[i].attached.phy_id = | ||
| 1426 | port_info->phy_info[i].phy_id; | ||
| 1192 | } | 1427 | } |
| 1193 | 1428 | ||
| 1194 | /* | 1429 | /* |
| @@ -1208,27 +1443,137 @@ mptsas_probe_expander_phys(MPT_ADAPTER *ioc, u32 *handle, int *index) | |||
| 1208 | mutex_unlock(&ioc->sas_topology_mutex); | 1443 | mutex_unlock(&ioc->sas_topology_mutex); |
| 1209 | 1444 | ||
| 1210 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], | 1445 | mptsas_probe_one_phy(parent, &port_info->phy_info[i], |
| 1211 | *index, 0); | 1446 | ioc->sas_index, 0); |
| 1212 | (*index)++; | 1447 | ioc->sas_index++; |
| 1213 | } | 1448 | } |
| 1214 | 1449 | ||
| 1215 | return 0; | 1450 | return 0; |
| 1216 | 1451 | ||
| 1217 | out_free_port_info: | 1452 | out_free_port_info: |
| 1218 | kfree(port_info); | 1453 | if (ex) { |
| 1454 | if (ex->phy_info) | ||
| 1455 | kfree(ex->phy_info); | ||
| 1456 | kfree(ex); | ||
| 1457 | } | ||
| 1219 | out: | 1458 | out: |
| 1220 | return error; | 1459 | return error; |
| 1221 | } | 1460 | } |
| 1222 | 1461 | ||
| 1462 | /* | ||
| 1463 | * mptsas_delete_expander_phys | ||
| 1464 | * | ||
| 1465 | * | ||
| 1466 | * This will traverse topology, and remove expanders | ||
| 1467 | * that are no longer present | ||
| 1468 | */ | ||
| 1469 | static void | ||
| 1470 | mptsas_delete_expander_phys(MPT_ADAPTER *ioc) | ||
| 1471 | { | ||
| 1472 | struct mptsas_portinfo buffer; | ||
| 1473 | struct mptsas_portinfo *port_info, *n, *parent; | ||
| 1474 | int i; | ||
| 1475 | |||
| 1476 | mutex_lock(&ioc->sas_topology_mutex); | ||
| 1477 | list_for_each_entry_safe(port_info, n, &ioc->sas_topology, list) { | ||
| 1478 | |||
| 1479 | if (port_info->phy_info && | ||
| 1480 | (!(port_info->phy_info[0].identify.device_info & | ||
| 1481 | MPI_SAS_DEVICE_INFO_SMP_TARGET))) | ||
| 1482 | continue; | ||
| 1483 | |||
| 1484 | if (mptsas_sas_expander_pg0(ioc, &buffer, | ||
| 1485 | (MPI_SAS_EXPAND_PGAD_FORM_HANDLE << | ||
| 1486 | MPI_SAS_EXPAND_PGAD_FORM_SHIFT), port_info->handle)) { | ||
| 1487 | |||
| 1488 | /* | ||
| 1489 | * Obtain the port_info instance to the parent port | ||
| 1490 | */ | ||
| 1491 | parent = mptsas_find_portinfo_by_handle(ioc, | ||
| 1492 | port_info->phy_info[0].identify.handle_parent); | ||
| 1493 | |||
| 1494 | if (!parent) | ||
| 1495 | goto next_port; | ||
| 1496 | |||
| 1497 | /* | ||
| 1498 | * Delete rphys in the parent that point | ||
| 1499 | * to this expander. The transport layer will | ||
| 1500 | * cleanup all the children. | ||
| 1501 | */ | ||
| 1502 | for (i = 0; i < parent->num_phys; i++) { | ||
| 1503 | if ((!parent->phy_info[i].rphy) || | ||
| 1504 | (parent->phy_info[i].attached.sas_address != | ||
| 1505 | port_info->phy_info[i].identify.sas_address)) | ||
| 1506 | continue; | ||
| 1507 | sas_rphy_delete(parent->phy_info[i].rphy); | ||
| 1508 | memset(&parent->phy_info[i].attached, 0, | ||
| 1509 | sizeof(struct mptsas_devinfo)); | ||
| 1510 | parent->phy_info[i].rphy = NULL; | ||
| 1511 | parent->phy_info[i].starget = NULL; | ||
| 1512 | } | ||
| 1513 | next_port: | ||
| 1514 | list_del(&port_info->list); | ||
| 1515 | if (port_info->phy_info) | ||
| 1516 | kfree(port_info->phy_info); | ||
| 1517 | kfree(port_info); | ||
| 1518 | } | ||
| 1519 | /* | ||
| 1520 | * Free this memory allocated from inside | ||
| 1521 | * mptsas_sas_expander_pg0 | ||
| 1522 | */ | ||
| 1523 | if (buffer.phy_info) | ||
| 1524 | kfree(buffer.phy_info); | ||
| 1525 | } | ||
| 1526 | mutex_unlock(&ioc->sas_topology_mutex); | ||
| 1527 | } | ||
| 1528 | |||
| 1529 | /* | ||
| 1530 | * Start of day discovery | ||
| 1531 | */ | ||
| 1223 | static void | 1532 | static void |
| 1224 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) | 1533 | mptsas_scan_sas_topology(MPT_ADAPTER *ioc) |
| 1225 | { | 1534 | { |
| 1226 | u32 handle = 0xFFFF; | 1535 | u32 handle = 0xFFFF; |
| 1227 | int index = 0; | 1536 | int i; |
| 1537 | |||
| 1538 | mutex_lock(&ioc->sas_discovery_mutex); | ||
| 1539 | mptsas_probe_hba_phys(ioc); | ||
| 1540 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
| 1541 | ; | ||
| 1542 | /* | ||
| 1543 | Reporting RAID volumes. | ||
| 1544 | */ | ||
| 1545 | if (!ioc->raid_data.pIocPg2) | ||
| 1546 | goto out; | ||
| 1547 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
| 1548 | goto out; | ||
| 1549 | for (i=0; i<ioc->raid_data.pIocPg2->NumActiveVolumes; i++) { | ||
| 1550 | scsi_add_device(ioc->sh, ioc->num_ports, | ||
| 1551 | ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0); | ||
| 1552 | } | ||
| 1553 | out: | ||
| 1554 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | /* | ||
| 1558 | * Work queue thread to handle Runtime discovery | ||
| 1559 | * Mere purpose is the hot add/delete of expanders | ||
| 1560 | */ | ||
| 1561 | static void | ||
| 1562 | mptscsih_discovery_work(void * arg) | ||
| 1563 | { | ||
| 1564 | struct mptsas_discovery_event *ev = arg; | ||
| 1565 | MPT_ADAPTER *ioc = ev->ioc; | ||
| 1566 | u32 handle = 0xFFFF; | ||
| 1228 | 1567 | ||
| 1229 | mptsas_probe_hba_phys(ioc, &index); | 1568 | mutex_lock(&ioc->sas_discovery_mutex); |
| 1230 | while (!mptsas_probe_expander_phys(ioc, &handle, &index)) | 1569 | ioc->sas_discovery_runtime=1; |
| 1570 | mptsas_delete_expander_phys(ioc); | ||
| 1571 | mptsas_probe_hba_phys(ioc); | ||
| 1572 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
| 1231 | ; | 1573 | ; |
| 1574 | kfree(ev); | ||
| 1575 | ioc->sas_discovery_runtime=0; | ||
| 1576 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
| 1232 | } | 1577 | } |
| 1233 | 1578 | ||
| 1234 | static struct mptsas_phyinfo * | 1579 | static struct mptsas_phyinfo * |
| @@ -1246,10 +1591,8 @@ mptsas_find_phyinfo_by_parent(MPT_ADAPTER *ioc, u16 parent_handle, u8 phy_id) | |||
| 1246 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << | 1591 | (MPI_SAS_DEVICE_PGAD_FORM_HANDLE << |
| 1247 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), | 1592 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), |
| 1248 | parent_handle); | 1593 | parent_handle); |
| 1249 | if (error) { | 1594 | if (error) |
| 1250 | printk("mptsas: failed to retrieve device page\n"); | ||
| 1251 | return NULL; | 1595 | return NULL; |
| 1252 | } | ||
| 1253 | 1596 | ||
| 1254 | /* | 1597 | /* |
| 1255 | * The phy_info structures are never deallocated during lifetime of | 1598 | * The phy_info structures are never deallocated during lifetime of |
| @@ -1296,6 +1639,35 @@ mptsas_find_phyinfo_by_target(MPT_ADAPTER *ioc, u32 id) | |||
| 1296 | return phy_info; | 1639 | return phy_info; |
| 1297 | } | 1640 | } |
| 1298 | 1641 | ||
| 1642 | /* | ||
| 1643 | * Work queue thread to clear the persitency table | ||
| 1644 | */ | ||
| 1645 | static void | ||
| 1646 | mptscsih_sas_persist_clear_table(void * arg) | ||
| 1647 | { | ||
| 1648 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | ||
| 1649 | |||
| 1650 | mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
| 1651 | } | ||
| 1652 | |||
| 1653 | static void | ||
| 1654 | mptsas_reprobe_lun(struct scsi_device *sdev, void *data) | ||
| 1655 | { | ||
| 1656 | sdev->no_uld_attach = data ? 1 : 0; | ||
| 1657 | scsi_device_reprobe(sdev); | ||
| 1658 | } | ||
| 1659 | |||
| 1660 | static void | ||
| 1661 | mptsas_reprobe_target(struct scsi_target *starget, int uld_attach) | ||
| 1662 | { | ||
| 1663 | starget_for_each_device(starget, uld_attach ? (void *)1 : NULL, | ||
| 1664 | mptsas_reprobe_lun); | ||
| 1665 | } | ||
| 1666 | |||
| 1667 | |||
| 1668 | /* | ||
| 1669 | * Work queue thread to handle SAS hotplug events | ||
| 1670 | */ | ||
| 1299 | static void | 1671 | static void |
| 1300 | mptsas_hotplug_work(void *arg) | 1672 | mptsas_hotplug_work(void *arg) |
| 1301 | { | 1673 | { |
| @@ -1304,16 +1676,39 @@ mptsas_hotplug_work(void *arg) | |||
| 1304 | struct mptsas_phyinfo *phy_info; | 1676 | struct mptsas_phyinfo *phy_info; |
| 1305 | struct sas_rphy *rphy; | 1677 | struct sas_rphy *rphy; |
| 1306 | struct scsi_device *sdev; | 1678 | struct scsi_device *sdev; |
| 1679 | struct sas_identify identify; | ||
| 1307 | char *ds = NULL; | 1680 | char *ds = NULL; |
| 1308 | struct mptsas_devinfo sas_device; | 1681 | struct mptsas_devinfo sas_device; |
| 1682 | VirtTarget *vtarget; | ||
| 1683 | |||
| 1684 | mutex_lock(&ioc->sas_discovery_mutex); | ||
| 1309 | 1685 | ||
| 1310 | switch (ev->event_type) { | 1686 | switch (ev->event_type) { |
| 1311 | case MPTSAS_DEL_DEVICE: | 1687 | case MPTSAS_DEL_DEVICE: |
| 1312 | 1688 | ||
| 1313 | phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); | 1689 | phy_info = mptsas_find_phyinfo_by_target(ioc, ev->id); |
| 1314 | if (!phy_info) { | 1690 | |
| 1315 | printk("mptsas: remove event for non-existant PHY.\n"); | 1691 | /* |
| 1692 | * Sanity checks, for non-existing phys and remote rphys. | ||
| 1693 | */ | ||
| 1694 | if (!phy_info) | ||
| 1316 | break; | 1695 | break; |
| 1696 | if (!phy_info->rphy) | ||
| 1697 | break; | ||
| 1698 | if (phy_info->starget) { | ||
| 1699 | vtarget = phy_info->starget->hostdata; | ||
| 1700 | |||
| 1701 | if (!vtarget) | ||
| 1702 | break; | ||
| 1703 | /* | ||
| 1704 | * Handling RAID components | ||
| 1705 | */ | ||
| 1706 | if (ev->phys_disk_num_valid) { | ||
| 1707 | vtarget->target_id = ev->phys_disk_num; | ||
| 1708 | vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
| 1709 | mptsas_reprobe_target(vtarget->starget, 1); | ||
| 1710 | break; | ||
| 1711 | } | ||
| 1317 | } | 1712 | } |
| 1318 | 1713 | ||
| 1319 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | 1714 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) |
| @@ -1327,55 +1722,74 @@ mptsas_hotplug_work(void *arg) | |||
| 1327 | "removing %s device, channel %d, id %d, phy %d\n", | 1722 | "removing %s device, channel %d, id %d, phy %d\n", |
| 1328 | ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); | 1723 | ioc->name, ds, ev->channel, ev->id, phy_info->phy_id); |
| 1329 | 1724 | ||
| 1330 | if (phy_info->rphy) { | 1725 | sas_rphy_delete(phy_info->rphy); |
| 1331 | sas_rphy_delete(phy_info->rphy); | 1726 | memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo)); |
| 1332 | phy_info->rphy = NULL; | 1727 | phy_info->rphy = NULL; |
| 1333 | } | 1728 | phy_info->starget = NULL; |
| 1334 | break; | 1729 | break; |
| 1335 | case MPTSAS_ADD_DEVICE: | 1730 | case MPTSAS_ADD_DEVICE: |
| 1336 | 1731 | ||
| 1337 | /* | 1732 | /* |
| 1338 | * When there is no sas address, | 1733 | * Refresh sas device pg0 data |
| 1339 | * RAID volumes are being deleted, | ||
| 1340 | * and hidden phy disk are being added. | ||
| 1341 | * We don't know the SAS data yet, | ||
| 1342 | * so lookup sas device page to get | ||
| 1343 | * pertaining info | ||
| 1344 | */ | 1734 | */ |
| 1345 | if (!ev->sas_address) { | 1735 | if (mptsas_sas_device_pg0(ioc, &sas_device, |
| 1346 | if (mptsas_sas_device_pg0(ioc, | 1736 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << |
| 1347 | &sas_device, ev->id, | 1737 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT), ev->id)) |
| 1348 | (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID << | 1738 | break; |
| 1349 | MPI_SAS_DEVICE_PGAD_FORM_SHIFT))) | ||
| 1350 | break; | ||
| 1351 | ev->handle = sas_device.handle; | ||
| 1352 | ev->parent_handle = sas_device.handle_parent; | ||
| 1353 | ev->channel = sas_device.channel; | ||
| 1354 | ev->phy_id = sas_device.phy_id; | ||
| 1355 | ev->sas_address = sas_device.sas_address; | ||
| 1356 | ev->device_info = sas_device.device_info; | ||
| 1357 | } | ||
| 1358 | 1739 | ||
| 1359 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | 1740 | phy_info = mptsas_find_phyinfo_by_parent(ioc, |
| 1360 | ev->parent_handle, ev->phy_id); | 1741 | sas_device.handle_parent, sas_device.phy_id); |
| 1742 | |||
| 1361 | if (!phy_info) { | 1743 | if (!phy_info) { |
| 1362 | printk("mptsas: add event for non-existant PHY.\n"); | 1744 | u32 handle = 0xFFFF; |
| 1363 | break; | 1745 | |
| 1746 | /* | ||
| 1747 | * Its possible when an expander has been hot added | ||
| 1748 | * containing attached devices, the sas firmware | ||
| 1749 | * may send a RC_ADDED event prior to the | ||
| 1750 | * DISCOVERY STOP event. If that occurs, our | ||
| 1751 | * view of the topology in the driver in respect to this | ||
| 1752 | * expander might of not been setup, and we hit this | ||
| 1753 | * condition. | ||
| 1754 | * Therefore, this code kicks off discovery to | ||
| 1755 | * refresh the data. | ||
| 1756 | * Then again, we check whether the parent phy has | ||
| 1757 | * been created. | ||
| 1758 | */ | ||
| 1759 | ioc->sas_discovery_runtime=1; | ||
| 1760 | mptsas_delete_expander_phys(ioc); | ||
| 1761 | mptsas_probe_hba_phys(ioc); | ||
| 1762 | while (!mptsas_probe_expander_phys(ioc, &handle)) | ||
| 1763 | ; | ||
| 1764 | ioc->sas_discovery_runtime=0; | ||
| 1765 | |||
| 1766 | phy_info = mptsas_find_phyinfo_by_parent(ioc, | ||
| 1767 | sas_device.handle_parent, sas_device.phy_id); | ||
| 1768 | if (!phy_info) | ||
| 1769 | break; | ||
| 1364 | } | 1770 | } |
| 1365 | 1771 | ||
| 1366 | if (phy_info->rphy) { | 1772 | if (phy_info->starget) { |
| 1367 | printk("mptsas: trying to add existing device.\n"); | 1773 | vtarget = phy_info->starget->hostdata; |
| 1774 | |||
| 1775 | if (!vtarget) | ||
| 1776 | break; | ||
| 1777 | /* | ||
| 1778 | * Handling RAID components | ||
| 1779 | */ | ||
| 1780 | if (vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT) { | ||
| 1781 | vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT; | ||
| 1782 | vtarget->target_id = ev->id; | ||
| 1783 | mptsas_reprobe_target(phy_info->starget, 0); | ||
| 1784 | } | ||
| 1368 | break; | 1785 | break; |
| 1369 | } | 1786 | } |
| 1370 | 1787 | ||
| 1371 | /* fill attached info */ | 1788 | if (phy_info->rphy) |
| 1372 | phy_info->attached.handle = ev->handle; | 1789 | break; |
| 1373 | phy_info->attached.phy_id = ev->phy_id; | 1790 | |
| 1374 | phy_info->attached.port_id = phy_info->identify.port_id; | 1791 | memcpy(&phy_info->attached, &sas_device, |
| 1375 | phy_info->attached.id = ev->id; | 1792 | sizeof(struct mptsas_devinfo)); |
| 1376 | phy_info->attached.channel = ev->channel; | ||
| 1377 | phy_info->attached.sas_address = ev->sas_address; | ||
| 1378 | phy_info->attached.device_info = ev->device_info; | ||
| 1379 | 1793 | ||
| 1380 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) | 1794 | if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_TARGET) |
| 1381 | ds = "ssp"; | 1795 | ds = "ssp"; |
| @@ -1388,13 +1802,23 @@ mptsas_hotplug_work(void *arg) | |||
| 1388 | "attaching %s device, channel %d, id %d, phy %d\n", | 1802 | "attaching %s device, channel %d, id %d, phy %d\n", |
| 1389 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); | 1803 | ioc->name, ds, ev->channel, ev->id, ev->phy_id); |
| 1390 | 1804 | ||
| 1391 | 1805 | mptsas_parse_device_info(&identify, &phy_info->attached); | |
| 1392 | rphy = sas_rphy_alloc(phy_info->phy); | 1806 | switch (identify.device_type) { |
| 1807 | case SAS_END_DEVICE: | ||
| 1808 | rphy = sas_end_device_alloc(phy_info->phy); | ||
| 1809 | break; | ||
| 1810 | case SAS_EDGE_EXPANDER_DEVICE: | ||
| 1811 | case SAS_FANOUT_EXPANDER_DEVICE: | ||
| 1812 | rphy = sas_expander_alloc(phy_info->phy, identify.device_type); | ||
| 1813 | break; | ||
| 1814 | default: | ||
| 1815 | rphy = NULL; | ||
| 1816 | break; | ||
| 1817 | } | ||
| 1393 | if (!rphy) | 1818 | if (!rphy) |
| 1394 | break; /* non-fatal: an rphy can be added later */ | 1819 | break; /* non-fatal: an rphy can be added later */ |
| 1395 | 1820 | ||
| 1396 | rphy->scsi_target_id = phy_info->attached.id; | 1821 | rphy->identify = identify; |
| 1397 | mptsas_parse_device_info(&rphy->identify, &phy_info->attached); | ||
| 1398 | if (sas_rphy_add(rphy)) { | 1822 | if (sas_rphy_add(rphy)) { |
| 1399 | sas_rphy_free(rphy); | 1823 | sas_rphy_free(rphy); |
| 1400 | break; | 1824 | break; |
| @@ -1413,7 +1837,7 @@ mptsas_hotplug_work(void *arg) | |||
| 1413 | break; | 1837 | break; |
| 1414 | } | 1838 | } |
| 1415 | printk(MYIOC_s_INFO_FMT | 1839 | printk(MYIOC_s_INFO_FMT |
| 1416 | "attaching device, channel %d, id %d\n", | 1840 | "attaching raid volume, channel %d, id %d\n", |
| 1417 | ioc->name, ioc->num_ports, ev->id); | 1841 | ioc->name, ioc->num_ports, ev->id); |
| 1418 | scsi_add_device(ioc->sh, | 1842 | scsi_add_device(ioc->sh, |
| 1419 | ioc->num_ports, | 1843 | ioc->num_ports, |
| @@ -1430,7 +1854,7 @@ mptsas_hotplug_work(void *arg) | |||
| 1430 | if (!sdev) | 1854 | if (!sdev) |
| 1431 | break; | 1855 | break; |
| 1432 | printk(MYIOC_s_INFO_FMT | 1856 | printk(MYIOC_s_INFO_FMT |
| 1433 | "removing device, channel %d, id %d\n", | 1857 | "removing raid volume, channel %d, id %d\n", |
| 1434 | ioc->name, ioc->num_ports, ev->id); | 1858 | ioc->name, ioc->num_ports, ev->id); |
| 1435 | scsi_remove_device(sdev); | 1859 | scsi_remove_device(sdev); |
| 1436 | scsi_device_put(sdev); | 1860 | scsi_device_put(sdev); |
| @@ -1439,6 +1863,7 @@ mptsas_hotplug_work(void *arg) | |||
| 1439 | } | 1863 | } |
| 1440 | 1864 | ||
| 1441 | kfree(ev); | 1865 | kfree(ev); |
| 1866 | mutex_unlock(&ioc->sas_discovery_mutex); | ||
| 1442 | } | 1867 | } |
| 1443 | 1868 | ||
| 1444 | static void | 1869 | static void |
| @@ -1455,35 +1880,51 @@ mptscsih_send_sas_event(MPT_ADAPTER *ioc, | |||
| 1455 | MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) | 1880 | MPI_SAS_DEVICE_INFO_SATA_DEVICE )) == 0) |
| 1456 | return; | 1881 | return; |
| 1457 | 1882 | ||
| 1458 | if ((sas_event_data->ReasonCode & | 1883 | switch (sas_event_data->ReasonCode) { |
| 1459 | (MPI_EVENT_SAS_DEV_STAT_RC_ADDED | | 1884 | case MPI_EVENT_SAS_DEV_STAT_RC_ADDED: |
| 1460 | MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING)) == 0) | 1885 | case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING: |
| 1461 | return; | 1886 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); |
| 1887 | if (!ev) { | ||
| 1888 | printk(KERN_WARNING "mptsas: lost hotplug event\n"); | ||
| 1889 | break; | ||
| 1890 | } | ||
| 1462 | 1891 | ||
| 1463 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); | 1892 | INIT_WORK(&ev->work, mptsas_hotplug_work, ev); |
| 1464 | if (!ev) { | 1893 | ev->ioc = ioc; |
| 1465 | printk(KERN_WARNING "mptsas: lost hotplug event\n"); | 1894 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); |
| 1466 | return; | 1895 | ev->parent_handle = |
| 1896 | le16_to_cpu(sas_event_data->ParentDevHandle); | ||
| 1897 | ev->channel = sas_event_data->Bus; | ||
| 1898 | ev->id = sas_event_data->TargetID; | ||
| 1899 | ev->phy_id = sas_event_data->PhyNum; | ||
| 1900 | memcpy(&sas_address, &sas_event_data->SASAddress, | ||
| 1901 | sizeof(__le64)); | ||
| 1902 | ev->sas_address = le64_to_cpu(sas_address); | ||
| 1903 | ev->device_info = device_info; | ||
| 1904 | |||
| 1905 | if (sas_event_data->ReasonCode & | ||
| 1906 | MPI_EVENT_SAS_DEV_STAT_RC_ADDED) | ||
| 1907 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
| 1908 | else | ||
| 1909 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
| 1910 | schedule_work(&ev->work); | ||
| 1911 | break; | ||
| 1912 | case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED: | ||
| 1913 | /* | ||
| 1914 | * Persistent table is full. | ||
| 1915 | */ | ||
| 1916 | INIT_WORK(&ioc->mptscsih_persistTask, | ||
| 1917 | mptscsih_sas_persist_clear_table, | ||
| 1918 | (void *)ioc); | ||
| 1919 | schedule_work(&ioc->mptscsih_persistTask); | ||
| 1920 | break; | ||
| 1921 | case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA: | ||
| 1922 | /* TODO */ | ||
| 1923 | case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET: | ||
| 1924 | /* TODO */ | ||
| 1925 | default: | ||
| 1926 | break; | ||
| 1467 | } | 1927 | } |
| 1468 | |||
| 1469 | |||
| 1470 | INIT_WORK(&ev->work, mptsas_hotplug_work, ev); | ||
| 1471 | ev->ioc = ioc; | ||
| 1472 | ev->handle = le16_to_cpu(sas_event_data->DevHandle); | ||
| 1473 | ev->parent_handle = le16_to_cpu(sas_event_data->ParentDevHandle); | ||
| 1474 | ev->channel = sas_event_data->Bus; | ||
| 1475 | ev->id = sas_event_data->TargetID; | ||
| 1476 | ev->phy_id = sas_event_data->PhyNum; | ||
| 1477 | memcpy(&sas_address, &sas_event_data->SASAddress, sizeof(__le64)); | ||
| 1478 | ev->sas_address = le64_to_cpu(sas_address); | ||
| 1479 | ev->device_info = device_info; | ||
| 1480 | |||
| 1481 | if (sas_event_data->ReasonCode & MPI_EVENT_SAS_DEV_STAT_RC_ADDED) | ||
| 1482 | ev->event_type = MPTSAS_ADD_DEVICE; | ||
| 1483 | else | ||
| 1484 | ev->event_type = MPTSAS_DEL_DEVICE; | ||
| 1485 | |||
| 1486 | schedule_work(&ev->work); | ||
| 1487 | } | 1928 | } |
| 1488 | 1929 | ||
| 1489 | static void | 1930 | static void |
| @@ -1512,6 +1953,9 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, | |||
| 1512 | ev->event_type = MPTSAS_ADD_DEVICE; | 1953 | ev->event_type = MPTSAS_ADD_DEVICE; |
| 1513 | break; | 1954 | break; |
| 1514 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: | 1955 | case MPI_EVENT_RAID_RC_PHYSDISK_CREATED: |
| 1956 | ioc->raid_data.isRaid = 1; | ||
| 1957 | ev->phys_disk_num_valid = 1; | ||
| 1958 | ev->phys_disk_num = raid_event_data->PhysDiskNum; | ||
| 1515 | ev->event_type = MPTSAS_DEL_DEVICE; | 1959 | ev->event_type = MPTSAS_DEL_DEVICE; |
| 1516 | break; | 1960 | break; |
| 1517 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: | 1961 | case MPI_EVENT_RAID_RC_VOLUME_DELETED: |
| @@ -1533,15 +1977,31 @@ mptscsih_send_raid_event(MPT_ADAPTER *ioc, | |||
| 1533 | schedule_work(&ev->work); | 1977 | schedule_work(&ev->work); |
| 1534 | } | 1978 | } |
| 1535 | 1979 | ||
| 1536 | /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ | ||
| 1537 | /* work queue thread to clear the persitency table */ | ||
| 1538 | static void | 1980 | static void |
| 1539 | mptscsih_sas_persist_clear_table(void * arg) | 1981 | mptscsih_send_discovery(MPT_ADAPTER *ioc, |
| 1982 | EVENT_DATA_SAS_DISCOVERY *discovery_data) | ||
| 1540 | { | 1983 | { |
| 1541 | MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; | 1984 | struct mptsas_discovery_event *ev; |
| 1985 | |||
| 1986 | /* | ||
| 1987 | * DiscoveryStatus | ||
| 1988 | * | ||
| 1989 | * This flag will be non-zero when firmware | ||
| 1990 | * kicks off discovery, and return to zero | ||
| 1991 | * once its completed. | ||
| 1992 | */ | ||
| 1993 | if (discovery_data->DiscoveryStatus) | ||
| 1994 | return; | ||
| 1995 | |||
| 1996 | ev = kmalloc(sizeof(*ev), GFP_ATOMIC); | ||
| 1997 | if (!ev) | ||
| 1998 | return; | ||
| 1999 | memset(ev,0,sizeof(struct mptsas_discovery_event)); | ||
| 2000 | INIT_WORK(&ev->work, mptscsih_discovery_work, ev); | ||
| 2001 | ev->ioc = ioc; | ||
| 2002 | schedule_work(&ev->work); | ||
| 2003 | }; | ||
| 1542 | 2004 | ||
| 1543 | mptbase_sas_persist_operation(ioc, MPI_SAS_OP_CLEAR_NOT_PRESENT); | ||
| 1544 | } | ||
| 1545 | 2005 | ||
| 1546 | static int | 2006 | static int |
| 1547 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | 2007 | mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) |
| @@ -1552,6 +2012,17 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | |||
| 1552 | if (!ioc->sh) | 2012 | if (!ioc->sh) |
| 1553 | goto out; | 2013 | goto out; |
| 1554 | 2014 | ||
| 2015 | /* | ||
| 2016 | * sas_discovery_ignore_events | ||
| 2017 | * | ||
| 2018 | * This flag is to prevent anymore processing of | ||
| 2019 | * sas events once mptsas_remove function is called. | ||
| 2020 | */ | ||
| 2021 | if (ioc->sas_discovery_ignore_events) { | ||
| 2022 | rc = mptscsih_event_process(ioc, reply); | ||
| 2023 | goto out; | ||
| 2024 | } | ||
| 2025 | |||
| 1555 | switch (event) { | 2026 | switch (event) { |
| 1556 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: | 2027 | case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE: |
| 1557 | mptscsih_send_sas_event(ioc, | 2028 | mptscsih_send_sas_event(ioc, |
| @@ -1567,6 +2038,10 @@ mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply) | |||
| 1567 | (void *)ioc); | 2038 | (void *)ioc); |
| 1568 | schedule_work(&ioc->mptscsih_persistTask); | 2039 | schedule_work(&ioc->mptscsih_persistTask); |
| 1569 | break; | 2040 | break; |
| 2041 | case MPI_EVENT_SAS_DISCOVERY: | ||
| 2042 | mptscsih_send_discovery(ioc, | ||
| 2043 | (EVENT_DATA_SAS_DISCOVERY *)reply->Data); | ||
| 2044 | break; | ||
| 1570 | default: | 2045 | default: |
| 1571 | rc = mptscsih_event_process(ioc, reply); | 2046 | rc = mptscsih_event_process(ioc, reply); |
| 1572 | break; | 2047 | break; |
| @@ -1668,7 +2143,7 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1668 | 2143 | ||
| 1669 | INIT_LIST_HEAD(&ioc->sas_topology); | 2144 | INIT_LIST_HEAD(&ioc->sas_topology); |
| 1670 | mutex_init(&ioc->sas_topology_mutex); | 2145 | mutex_init(&ioc->sas_topology_mutex); |
| 1671 | 2146 | mutex_init(&ioc->sas_discovery_mutex); | |
| 1672 | mutex_init(&ioc->sas_mgmt.mutex); | 2147 | mutex_init(&ioc->sas_mgmt.mutex); |
| 1673 | init_completion(&ioc->sas_mgmt.done); | 2148 | init_completion(&ioc->sas_mgmt.done); |
| 1674 | 2149 | ||
| @@ -1781,20 +2256,6 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
| 1781 | 2256 | ||
| 1782 | mptsas_scan_sas_topology(ioc); | 2257 | mptsas_scan_sas_topology(ioc); |
| 1783 | 2258 | ||
| 1784 | /* | ||
| 1785 | Reporting RAID volumes. | ||
| 1786 | */ | ||
| 1787 | if (!ioc->raid_data.pIocPg2) | ||
| 1788 | return 0; | ||
| 1789 | if (!ioc->raid_data.pIocPg2->NumActiveVolumes) | ||
| 1790 | return 0; | ||
| 1791 | for (ii=0;ii<ioc->raid_data.pIocPg2->NumActiveVolumes;ii++) { | ||
| 1792 | scsi_add_device(sh, | ||
| 1793 | ioc->num_ports, | ||
| 1794 | ioc->raid_data.pIocPg2->RaidVolume[ii].VolumeID, | ||
| 1795 | 0); | ||
| 1796 | } | ||
| 1797 | |||
| 1798 | return 0; | 2259 | return 0; |
| 1799 | 2260 | ||
| 1800 | out_mptsas_probe: | 2261 | out_mptsas_probe: |
| @@ -1808,11 +2269,14 @@ static void __devexit mptsas_remove(struct pci_dev *pdev) | |||
| 1808 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); | 2269 | MPT_ADAPTER *ioc = pci_get_drvdata(pdev); |
| 1809 | struct mptsas_portinfo *p, *n; | 2270 | struct mptsas_portinfo *p, *n; |
| 1810 | 2271 | ||
| 2272 | ioc->sas_discovery_ignore_events=1; | ||
| 1811 | sas_remove_host(ioc->sh); | 2273 | sas_remove_host(ioc->sh); |
| 1812 | 2274 | ||
| 1813 | mutex_lock(&ioc->sas_topology_mutex); | 2275 | mutex_lock(&ioc->sas_topology_mutex); |
| 1814 | list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { | 2276 | list_for_each_entry_safe(p, n, &ioc->sas_topology, list) { |
| 1815 | list_del(&p->list); | 2277 | list_del(&p->list); |
| 2278 | if (p->phy_info) | ||
| 2279 | kfree(p->phy_info); | ||
| 1816 | kfree(p); | 2280 | kfree(p); |
| 1817 | } | 2281 | } |
| 1818 | mutex_unlock(&ioc->sas_topology_mutex); | 2282 | mutex_unlock(&ioc->sas_topology_mutex); |
| @@ -1867,7 +2331,7 @@ mptsas_init(void) | |||
| 1867 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); | 2331 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); |
| 1868 | 2332 | ||
| 1869 | if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) { | 2333 | if (mpt_event_register(mptsasDoneCtx, mptsas_event_process) == 0) { |
| 1870 | devtprintk((KERN_INFO MYNAM | 2334 | devtverboseprintk((KERN_INFO MYNAM |
| 1871 | ": Registered for IOC event notifications\n")); | 2335 | ": Registered for IOC event notifications\n")); |
| 1872 | } | 2336 | } |
| 1873 | 2337 | ||
