diff options
-rw-r--r-- | drivers/scsi/isci/host.c | 201 | ||||
-rw-r--r-- | drivers/scsi/isci/init.c | 91 | ||||
-rw-r--r-- | drivers/scsi/isci/isci.h | 1 |
3 files changed, 134 insertions, 159 deletions
diff --git a/drivers/scsi/isci/host.c b/drivers/scsi/isci/host.c index cb2e3f9558e9..aa86615fa7a9 100644 --- a/drivers/scsi/isci/host.c +++ b/drivers/scsi/isci/host.c | |||
@@ -354,67 +354,6 @@ void isci_host_deinit(struct isci_host *ihost) | |||
354 | scic_controller_reset(scic); | 354 | scic_controller_reset(scic); |
355 | } | 355 | } |
356 | 356 | ||
357 | static int isci_verify_firmware(const struct firmware *fw, | ||
358 | struct isci_firmware *isci_fw) | ||
359 | { | ||
360 | const u8 *tmp; | ||
361 | |||
362 | if (fw->size < ISCI_FIRMWARE_MIN_SIZE) | ||
363 | return -EINVAL; | ||
364 | |||
365 | tmp = fw->data; | ||
366 | |||
367 | /* 12th char should be the NULL terminate for the ID string */ | ||
368 | if (tmp[11] != '\0') | ||
369 | return -EINVAL; | ||
370 | |||
371 | if (strncmp("#SCU MAGIC#", tmp, 11) != 0) | ||
372 | return -EINVAL; | ||
373 | |||
374 | isci_fw->id = tmp; | ||
375 | isci_fw->version = fw->data[ISCI_FW_VER_OFS]; | ||
376 | isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS]; | ||
377 | |||
378 | tmp = fw->data + ISCI_FW_DATA_OFS; | ||
379 | |||
380 | while (*tmp != ISCI_FW_HDR_EOF) { | ||
381 | switch (*tmp) { | ||
382 | case ISCI_FW_HDR_PHYMASK: | ||
383 | tmp++; | ||
384 | isci_fw->phy_masks_size = *tmp; | ||
385 | tmp++; | ||
386 | isci_fw->phy_masks = (const u32 *)tmp; | ||
387 | tmp += sizeof(u32) * isci_fw->phy_masks_size; | ||
388 | break; | ||
389 | |||
390 | case ISCI_FW_HDR_PHYGEN: | ||
391 | tmp++; | ||
392 | isci_fw->phy_gens_size = *tmp; | ||
393 | tmp++; | ||
394 | isci_fw->phy_gens = (const u32 *)tmp; | ||
395 | tmp += sizeof(u32) * isci_fw->phy_gens_size; | ||
396 | break; | ||
397 | |||
398 | case ISCI_FW_HDR_SASADDR: | ||
399 | tmp++; | ||
400 | isci_fw->sas_addrs_size = *tmp; | ||
401 | tmp++; | ||
402 | isci_fw->sas_addrs = (const u64 *)tmp; | ||
403 | tmp += sizeof(u64) * isci_fw->sas_addrs_size; | ||
404 | break; | ||
405 | |||
406 | default: | ||
407 | pr_err("bad field in firmware binary blob\n"); | ||
408 | return -EINVAL; | ||
409 | } | ||
410 | } | ||
411 | |||
412 | pr_info("isci firmware v%u.%u loaded.\n", | ||
413 | isci_fw->version, isci_fw->subversion); | ||
414 | |||
415 | return SCI_SUCCESS; | ||
416 | } | ||
417 | |||
418 | static void __iomem *scu_base(struct isci_host *isci_host) | 357 | static void __iomem *scu_base(struct isci_host *isci_host) |
419 | { | 358 | { |
420 | struct pci_dev *pdev = isci_host->pdev; | 359 | struct pci_dev *pdev = isci_host->pdev; |
@@ -442,8 +381,6 @@ int isci_host_init(struct isci_host *isci_host) | |||
442 | struct scic_sds_port *scic_port; | 381 | struct scic_sds_port *scic_port; |
443 | union scic_oem_parameters scic_oem_params; | 382 | union scic_oem_parameters scic_oem_params; |
444 | union scic_user_parameters scic_user_params; | 383 | union scic_user_parameters scic_user_params; |
445 | const struct firmware *fw = NULL; | ||
446 | struct isci_firmware *isci_fw = NULL; | ||
447 | 384 | ||
448 | INIT_LIST_HEAD(&isci_host->timer_list_struct.timers); | 385 | INIT_LIST_HEAD(&isci_host->timer_list_struct.timers); |
449 | isci_timer_list_construct( | 386 | isci_timer_list_construct( |
@@ -454,9 +391,11 @@ int isci_host_init(struct isci_host *isci_host) | |||
454 | controller = scic_controller_alloc(&isci_host->pdev->dev); | 391 | controller = scic_controller_alloc(&isci_host->pdev->dev); |
455 | 392 | ||
456 | if (!controller) { | 393 | if (!controller) { |
457 | err = -ENOMEM; | 394 | dev_err(&isci_host->pdev->dev, |
458 | dev_err(&isci_host->pdev->dev, "%s: failed (%d)\n", __func__, err); | 395 | "%s: failed (%d)\n", |
459 | goto out; | 396 | __func__, |
397 | err); | ||
398 | return -ENOMEM; | ||
460 | } | 399 | } |
461 | 400 | ||
462 | isci_host->core_controller = controller; | 401 | isci_host->core_controller = controller; |
@@ -476,8 +415,7 @@ int isci_host_init(struct isci_host *isci_host) | |||
476 | "%s: scic_controller_construct failed - status = %x\n", | 415 | "%s: scic_controller_construct failed - status = %x\n", |
477 | __func__, | 416 | __func__, |
478 | status); | 417 | status); |
479 | err = -ENODEV; | 418 | return -ENODEV; |
480 | goto out; | ||
481 | } | 419 | } |
482 | 420 | ||
483 | isci_host->sas_ha.dev = &isci_host->pdev->dev; | 421 | isci_host->sas_ha.dev = &isci_host->pdev->dev; |
@@ -487,93 +425,52 @@ int isci_host_init(struct isci_host *isci_host) | |||
487 | * set association host adapter struct in core controller. | 425 | * set association host adapter struct in core controller. |
488 | */ | 426 | */ |
489 | sci_object_set_association(isci_host->core_controller, | 427 | sci_object_set_association(isci_host->core_controller, |
490 | (void *)isci_host | 428 | (void *)isci_host); |
491 | ); | ||
492 | 429 | ||
493 | /* grab initial values stored in the controller object for OEM and USER | 430 | /* grab initial values stored in the controller object for OEM and USER |
494 | * parameters */ | 431 | * parameters */ |
495 | scic_oem_parameters_get(controller, &scic_oem_params); | 432 | scic_oem_parameters_get(controller, &scic_oem_params); |
496 | scic_user_parameters_get(controller, &scic_user_params); | 433 | scic_user_parameters_get(controller, &scic_user_params); |
497 | 434 | ||
498 | isci_fw = devm_kzalloc(&isci_host->pdev->dev, | 435 | if (isci_firmware) { |
499 | sizeof(struct isci_firmware), | 436 | /* grab any OEM and USER parameters specified in binary blob */ |
500 | GFP_KERNEL); | ||
501 | if (!isci_fw) { | ||
502 | dev_warn(&isci_host->pdev->dev, | ||
503 | "allocating firmware struct failed\n"); | ||
504 | dev_warn(&isci_host->pdev->dev, | ||
505 | "Default OEM configuration being used:" | ||
506 | " 4 narrow ports, and default SAS Addresses\n"); | ||
507 | goto set_default_params; | ||
508 | } | ||
509 | |||
510 | status = request_firmware(&fw, ISCI_FW_NAME, &isci_host->pdev->dev); | ||
511 | if (status) { | ||
512 | dev_warn(&isci_host->pdev->dev, | ||
513 | "Loading firmware failed, using default values\n"); | ||
514 | dev_warn(&isci_host->pdev->dev, | ||
515 | "Default OEM configuration being used:" | ||
516 | " 4 narrow ports, and default SAS Addresses\n"); | ||
517 | goto set_default_params; | ||
518 | } | ||
519 | else { | ||
520 | status = isci_verify_firmware(fw, isci_fw); | ||
521 | if (status != SCI_SUCCESS) { | ||
522 | dev_warn(&isci_host->pdev->dev, | ||
523 | "firmware verification failed\n"); | ||
524 | dev_warn(&isci_host->pdev->dev, | ||
525 | "Default OEM configuration being used:" | ||
526 | " 4 narrow ports, and default SAS " | ||
527 | "Addresses\n"); | ||
528 | goto set_default_params; | ||
529 | } | ||
530 | |||
531 | /* grab any OEM and USER parameters specified at module load */ | ||
532 | status = isci_parse_oem_parameters(&scic_oem_params, | 437 | status = isci_parse_oem_parameters(&scic_oem_params, |
533 | isci_host->id, isci_fw); | 438 | isci_host->id, |
439 | isci_firmware); | ||
534 | if (status != SCI_SUCCESS) { | 440 | if (status != SCI_SUCCESS) { |
535 | dev_warn(&isci_host->pdev->dev, | 441 | dev_warn(&isci_host->pdev->dev, |
536 | "parsing firmware oem parameters failed\n"); | 442 | "parsing firmware oem parameters failed\n"); |
537 | err = -EINVAL; | 443 | return -EINVAL; |
538 | goto out; | ||
539 | } | 444 | } |
540 | 445 | ||
541 | status = isci_parse_user_parameters(&scic_user_params, | 446 | status = isci_parse_user_parameters(&scic_user_params, |
542 | isci_host->id, isci_fw); | 447 | isci_host->id, |
448 | isci_firmware); | ||
543 | if (status != SCI_SUCCESS) { | 449 | if (status != SCI_SUCCESS) { |
544 | dev_warn(&isci_host->pdev->dev, | 450 | dev_warn(&isci_host->pdev->dev, |
545 | "%s: isci_parse_user_parameters" | 451 | "%s: isci_parse_user_parameters" |
546 | " failed\n", __func__); | 452 | " failed\n", __func__); |
547 | err = -EINVAL; | 453 | return -EINVAL; |
548 | goto out; | 454 | } |
455 | } else { | ||
456 | status = scic_oem_parameters_set(isci_host->core_controller, | ||
457 | &scic_oem_params); | ||
458 | if (status != SCI_SUCCESS) { | ||
459 | dev_warn(&isci_host->pdev->dev, | ||
460 | "%s: scic_oem_parameters_set failed\n", | ||
461 | __func__); | ||
462 | return -ENODEV; | ||
549 | } | 463 | } |
550 | } | ||
551 | |||
552 | set_default_params: | ||
553 | |||
554 | status = scic_oem_parameters_set(isci_host->core_controller, | ||
555 | &scic_oem_params | ||
556 | ); | ||
557 | |||
558 | if (status != SCI_SUCCESS) { | ||
559 | dev_warn(&isci_host->pdev->dev, | ||
560 | "%s: scic_oem_parameters_set failed\n", | ||
561 | __func__); | ||
562 | err = -ENODEV; | ||
563 | goto out; | ||
564 | } | ||
565 | |||
566 | 464 | ||
567 | status = scic_user_parameters_set(isci_host->core_controller, | ||
568 | &scic_user_params | ||
569 | ); | ||
570 | 465 | ||
571 | if (status != SCI_SUCCESS) { | 466 | status = scic_user_parameters_set(isci_host->core_controller, |
572 | dev_warn(&isci_host->pdev->dev, | 467 | &scic_user_params); |
573 | "%s: scic_user_parameters_set failed\n", | 468 | if (status != SCI_SUCCESS) { |
574 | __func__); | 469 | dev_warn(&isci_host->pdev->dev, |
575 | err = -ENODEV; | 470 | "%s: scic_user_parameters_set failed\n", |
576 | goto out; | 471 | __func__); |
472 | return -ENODEV; | ||
473 | } | ||
577 | } | 474 | } |
578 | 475 | ||
579 | status = scic_controller_initialize(isci_host->core_controller); | 476 | status = scic_controller_initialize(isci_host->core_controller); |
@@ -582,8 +479,7 @@ int isci_host_init(struct isci_host *isci_host) | |||
582 | "%s: scic_controller_initialize failed -" | 479 | "%s: scic_controller_initialize failed -" |
583 | " status = 0x%x\n", | 480 | " status = 0x%x\n", |
584 | __func__, status); | 481 | __func__, status); |
585 | err = -ENODEV; | 482 | return -ENODEV; |
586 | goto out; | ||
587 | } | 483 | } |
588 | 484 | ||
589 | tasklet_init(&isci_host->completion_tasklet, | 485 | tasklet_init(&isci_host->completion_tasklet, |
@@ -598,7 +494,7 @@ int isci_host_init(struct isci_host *isci_host) | |||
598 | err = isci_host_mdl_allocate_coherent(isci_host); | 494 | err = isci_host_mdl_allocate_coherent(isci_host); |
599 | 495 | ||
600 | if (err) | 496 | if (err) |
601 | goto err_out; | 497 | return err; |
602 | 498 | ||
603 | /* | 499 | /* |
604 | * keep the pool alloc size around, will use it for a bounds checking | 500 | * keep the pool alloc size around, will use it for a bounds checking |
@@ -610,40 +506,27 @@ int isci_host_init(struct isci_host *isci_host) | |||
610 | isci_host->dma_pool_alloc_size, | 506 | isci_host->dma_pool_alloc_size, |
611 | SLAB_HWCACHE_ALIGN, 0); | 507 | SLAB_HWCACHE_ALIGN, 0); |
612 | 508 | ||
613 | if (!isci_host->dma_pool) { | 509 | if (!isci_host->dma_pool) |
614 | err = -ENOMEM; | 510 | return -ENOMEM; |
615 | goto req_obj_err_out; | ||
616 | } | ||
617 | 511 | ||
618 | for (index = 0; index < SCI_MAX_PORTS; index++) { | 512 | for (index = 0; index < SCI_MAX_PORTS; index++) |
619 | isci_port_init(&isci_host->isci_ports[index], | 513 | isci_port_init(&isci_host->isci_ports[index], |
620 | isci_host, index); | 514 | isci_host, |
621 | } | 515 | index); |
622 | 516 | ||
623 | for (index = 0; index < SCI_MAX_PHYS; index++) | 517 | for (index = 0; index < SCI_MAX_PHYS; index++) |
624 | isci_phy_init(&isci_host->phys[index], isci_host, index); | 518 | isci_phy_init(&isci_host->phys[index], isci_host, index); |
625 | 519 | ||
626 | /* Why are we doing this? Is this even necessary? */ | 520 | /* Why are we doing this? Is this even necessary? */ |
627 | memcpy(&isci_host->sas_addr[0], &isci_host->phys[0].sas_addr[0], | 521 | memcpy(&isci_host->sas_addr[0], |
522 | &isci_host->phys[0].sas_addr[0], | ||
628 | SAS_ADDR_SIZE); | 523 | SAS_ADDR_SIZE); |
629 | 524 | ||
630 | /* Start the ports */ | 525 | /* Start the ports */ |
631 | for (index = 0; index < SCI_MAX_PORTS; index++) { | 526 | for (index = 0; index < SCI_MAX_PORTS; index++) { |
632 | |||
633 | scic_controller_get_port_handle(controller, index, &scic_port); | 527 | scic_controller_get_port_handle(controller, index, &scic_port); |
634 | scic_port_start(scic_port); | 528 | scic_port_start(scic_port); |
635 | } | 529 | } |
636 | 530 | ||
637 | goto out; | 531 | return 0; |
638 | |||
639 | /* SPB_Debug: destroy request object cache */ | ||
640 | req_obj_err_out: | ||
641 | /* SPB_Debug: destroy remote object cache */ | ||
642 | err_out: | ||
643 | /* SPB_Debug: undo controller init, construct and alloc, remove from parent | ||
644 | * controller list. */ | ||
645 | out: | ||
646 | if (fw) | ||
647 | release_firmware(fw); | ||
648 | return err; | ||
649 | } | 532 | } |
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index fda26292ba2b..6ca623aff051 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c | |||
@@ -82,6 +82,8 @@ static DEFINE_PCI_DEVICE_TABLE(isci_id_table) = { | |||
82 | {} | 82 | {} |
83 | }; | 83 | }; |
84 | 84 | ||
85 | struct isci_firmware *isci_firmware; | ||
86 | |||
85 | static int __devinit isci_pci_probe( | 87 | static int __devinit isci_pci_probe( |
86 | struct pci_dev *pdev, | 88 | struct pci_dev *pdev, |
87 | const struct pci_device_id *device_id_p); | 89 | const struct pci_device_id *device_id_p); |
@@ -519,11 +521,73 @@ static void check_si_rev(struct pci_dev *pdev) | |||
519 | 521 | ||
520 | } | 522 | } |
521 | 523 | ||
524 | static int isci_verify_firmware(const struct firmware *fw, | ||
525 | struct isci_firmware *isci_fw) | ||
526 | { | ||
527 | const u8 *tmp; | ||
528 | |||
529 | if (fw->size < ISCI_FIRMWARE_MIN_SIZE) | ||
530 | return -EINVAL; | ||
531 | |||
532 | tmp = fw->data; | ||
533 | |||
534 | /* 12th char should be the NULL terminate for the ID string */ | ||
535 | if (tmp[11] != '\0') | ||
536 | return -EINVAL; | ||
537 | |||
538 | if (strncmp("#SCU MAGIC#", tmp, 11) != 0) | ||
539 | return -EINVAL; | ||
540 | |||
541 | isci_fw->id = tmp; | ||
542 | isci_fw->version = fw->data[ISCI_FW_VER_OFS]; | ||
543 | isci_fw->subversion = fw->data[ISCI_FW_SUBVER_OFS]; | ||
544 | |||
545 | tmp = fw->data + ISCI_FW_DATA_OFS; | ||
546 | |||
547 | while (*tmp != ISCI_FW_HDR_EOF) { | ||
548 | switch (*tmp) { | ||
549 | case ISCI_FW_HDR_PHYMASK: | ||
550 | tmp++; | ||
551 | isci_fw->phy_masks_size = *tmp; | ||
552 | tmp++; | ||
553 | isci_fw->phy_masks = (const u32 *)tmp; | ||
554 | tmp += sizeof(u32) * isci_fw->phy_masks_size; | ||
555 | break; | ||
556 | |||
557 | case ISCI_FW_HDR_PHYGEN: | ||
558 | tmp++; | ||
559 | isci_fw->phy_gens_size = *tmp; | ||
560 | tmp++; | ||
561 | isci_fw->phy_gens = (const u32 *)tmp; | ||
562 | tmp += sizeof(u32) * isci_fw->phy_gens_size; | ||
563 | break; | ||
564 | |||
565 | case ISCI_FW_HDR_SASADDR: | ||
566 | tmp++; | ||
567 | isci_fw->sas_addrs_size = *tmp; | ||
568 | tmp++; | ||
569 | isci_fw->sas_addrs = (const u64 *)tmp; | ||
570 | tmp += sizeof(u64) * isci_fw->sas_addrs_size; | ||
571 | break; | ||
572 | |||
573 | default: | ||
574 | pr_err("bad field in firmware binary blob\n"); | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | } | ||
578 | |||
579 | pr_info("isci firmware v%u.%u loaded.\n", | ||
580 | isci_fw->version, isci_fw->subversion); | ||
581 | |||
582 | return SCI_SUCCESS; | ||
583 | } | ||
584 | |||
522 | static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 585 | static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
523 | { | 586 | { |
524 | struct isci_pci_info *pci_info; | 587 | struct isci_pci_info *pci_info; |
525 | int err, i; | 588 | int err, i; |
526 | struct isci_host *isci_host; | 589 | struct isci_host *isci_host; |
590 | const struct firmware *fw = NULL; | ||
527 | 591 | ||
528 | check_si_rev(pdev); | 592 | check_si_rev(pdev); |
529 | 593 | ||
@@ -532,6 +596,33 @@ static int __devinit isci_pci_probe(struct pci_dev *pdev, const struct pci_devic | |||
532 | return -ENOMEM; | 596 | return -ENOMEM; |
533 | pci_set_drvdata(pdev, pci_info); | 597 | pci_set_drvdata(pdev, pci_info); |
534 | 598 | ||
599 | err = request_firmware(&fw, ISCI_FW_NAME, &pdev->dev); | ||
600 | if (err) { | ||
601 | dev_warn(&pdev->dev, | ||
602 | "Loading firmware failed, using default values\n"); | ||
603 | dev_warn(&pdev->dev, | ||
604 | "Default OEM configuration being used:" | ||
605 | " 4 narrow ports, and default SAS Addresses\n"); | ||
606 | } else { | ||
607 | isci_firmware = devm_kzalloc(&pdev->dev, | ||
608 | sizeof(struct isci_firmware), | ||
609 | GFP_KERNEL); | ||
610 | if (isci_firmware) { | ||
611 | err = isci_verify_firmware(fw, isci_firmware); | ||
612 | if (err != SCI_SUCCESS) { | ||
613 | dev_warn(&pdev->dev, | ||
614 | "firmware verification failed\n"); | ||
615 | dev_warn(&pdev->dev, | ||
616 | "Default OEM configuration being used:" | ||
617 | " 4 narrow ports, and default SAS " | ||
618 | "Addresses\n"); | ||
619 | devm_kfree(&pdev->dev, isci_firmware); | ||
620 | isci_firmware = NULL; | ||
621 | } | ||
622 | } | ||
623 | release_firmware(fw); | ||
624 | } | ||
625 | |||
535 | err = isci_pci_init(pdev); | 626 | err = isci_pci_init(pdev); |
536 | if (err) | 627 | if (err) |
537 | return err; | 628 | return err; |
diff --git a/drivers/scsi/isci/isci.h b/drivers/scsi/isci/isci.h index 39efd5f27200..6c79b29f3102 100644 --- a/drivers/scsi/isci/isci.h +++ b/drivers/scsi/isci/isci.h | |||
@@ -86,6 +86,7 @@ | |||
86 | #include "sci_status.h" | 86 | #include "sci_status.h" |
87 | 87 | ||
88 | extern struct kmem_cache *isci_kmem_cache; | 88 | extern struct kmem_cache *isci_kmem_cache; |
89 | extern struct isci_firmware *isci_firmware; | ||
89 | 90 | ||
90 | #define ISCI_FW_NAME "isci/isci_firmware.bin" | 91 | #define ISCI_FW_NAME "isci/isci_firmware.bin" |
91 | 92 | ||