diff options
Diffstat (limited to 'drivers/scsi/isci/init.c')
-rw-r--r-- | drivers/scsi/isci/init.c | 199 |
1 files changed, 182 insertions, 17 deletions
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c index 5137db5a5d85..eda43851cc98 100644 --- a/drivers/scsi/isci/init.c +++ b/drivers/scsi/isci/init.c | |||
@@ -397,38 +397,203 @@ static int isci_setup_interrupts(struct pci_dev *pdev) | |||
397 | return err; | 397 | return err; |
398 | } | 398 | } |
399 | 399 | ||
400 | static void isci_user_parameters_get(struct sci_user_parameters *u) | ||
401 | { | ||
402 | int i; | ||
403 | |||
404 | for (i = 0; i < SCI_MAX_PHYS; i++) { | ||
405 | struct sci_phy_user_params *u_phy = &u->phys[i]; | ||
406 | |||
407 | u_phy->max_speed_generation = phy_gen; | ||
408 | |||
409 | /* we are not exporting these for now */ | ||
410 | u_phy->align_insertion_frequency = 0x7f; | ||
411 | u_phy->in_connection_align_insertion_frequency = 0xff; | ||
412 | u_phy->notify_enable_spin_up_insertion_frequency = 0x33; | ||
413 | } | ||
414 | |||
415 | u->stp_inactivity_timeout = stp_inactive_to; | ||
416 | u->ssp_inactivity_timeout = ssp_inactive_to; | ||
417 | u->stp_max_occupancy_timeout = stp_max_occ_to; | ||
418 | u->ssp_max_occupancy_timeout = ssp_max_occ_to; | ||
419 | u->no_outbound_task_timeout = no_outbound_task_to; | ||
420 | u->max_concurr_spinup = max_concurr_spinup; | ||
421 | } | ||
422 | |||
423 | static enum sci_status sci_user_parameters_set(struct isci_host *ihost, | ||
424 | struct sci_user_parameters *sci_parms) | ||
425 | { | ||
426 | u16 index; | ||
427 | |||
428 | /* | ||
429 | * Validate the user parameters. If they are not legal, then | ||
430 | * return a failure. | ||
431 | */ | ||
432 | for (index = 0; index < SCI_MAX_PHYS; index++) { | ||
433 | struct sci_phy_user_params *u; | ||
434 | |||
435 | u = &sci_parms->phys[index]; | ||
436 | |||
437 | if (!((u->max_speed_generation <= SCIC_SDS_PARM_MAX_SPEED) && | ||
438 | (u->max_speed_generation > SCIC_SDS_PARM_NO_SPEED))) | ||
439 | return SCI_FAILURE_INVALID_PARAMETER_VALUE; | ||
440 | |||
441 | if (u->in_connection_align_insertion_frequency < 3) | ||
442 | return SCI_FAILURE_INVALID_PARAMETER_VALUE; | ||
443 | |||
444 | if ((u->in_connection_align_insertion_frequency < 3) || | ||
445 | (u->align_insertion_frequency == 0) || | ||
446 | (u->notify_enable_spin_up_insertion_frequency == 0)) | ||
447 | return SCI_FAILURE_INVALID_PARAMETER_VALUE; | ||
448 | } | ||
449 | |||
450 | if ((sci_parms->stp_inactivity_timeout == 0) || | ||
451 | (sci_parms->ssp_inactivity_timeout == 0) || | ||
452 | (sci_parms->stp_max_occupancy_timeout == 0) || | ||
453 | (sci_parms->ssp_max_occupancy_timeout == 0) || | ||
454 | (sci_parms->no_outbound_task_timeout == 0)) | ||
455 | return SCI_FAILURE_INVALID_PARAMETER_VALUE; | ||
456 | |||
457 | memcpy(&ihost->user_parameters, sci_parms, sizeof(*sci_parms)); | ||
458 | |||
459 | return SCI_SUCCESS; | ||
460 | } | ||
461 | |||
462 | static void sci_oem_defaults(struct isci_host *ihost) | ||
463 | { | ||
464 | /* these defaults are overridden by the platform / firmware */ | ||
465 | struct sci_user_parameters *user = &ihost->user_parameters; | ||
466 | struct sci_oem_params *oem = &ihost->oem_parameters; | ||
467 | int i; | ||
468 | |||
469 | /* Default to APC mode. */ | ||
470 | oem->controller.mode_type = SCIC_PORT_AUTOMATIC_CONFIGURATION_MODE; | ||
471 | |||
472 | /* Default to APC mode. */ | ||
473 | oem->controller.max_concurr_spin_up = 1; | ||
474 | |||
475 | /* Default to no SSC operation. */ | ||
476 | oem->controller.do_enable_ssc = false; | ||
477 | |||
478 | /* Default to short cables on all phys. */ | ||
479 | oem->controller.cable_selection_mask = 0; | ||
480 | |||
481 | /* Initialize all of the port parameter information to narrow ports. */ | ||
482 | for (i = 0; i < SCI_MAX_PORTS; i++) | ||
483 | oem->ports[i].phy_mask = 0; | ||
484 | |||
485 | /* Initialize all of the phy parameter information. */ | ||
486 | for (i = 0; i < SCI_MAX_PHYS; i++) { | ||
487 | /* Default to 3G (i.e. Gen 2). */ | ||
488 | user->phys[i].max_speed_generation = SCIC_SDS_PARM_GEN2_SPEED; | ||
489 | |||
490 | /* the frequencies cannot be 0 */ | ||
491 | user->phys[i].align_insertion_frequency = 0x7f; | ||
492 | user->phys[i].in_connection_align_insertion_frequency = 0xff; | ||
493 | user->phys[i].notify_enable_spin_up_insertion_frequency = 0x33; | ||
494 | |||
495 | /* Previous Vitesse based expanders had a arbitration issue that | ||
496 | * is worked around by having the upper 32-bits of SAS address | ||
497 | * with a value greater then the Vitesse company identifier. | ||
498 | * Hence, usage of 0x5FCFFFFF. | ||
499 | */ | ||
500 | oem->phys[i].sas_address.low = 0x1 + ihost->id; | ||
501 | oem->phys[i].sas_address.high = 0x5FCFFFFF; | ||
502 | } | ||
503 | |||
504 | user->stp_inactivity_timeout = 5; | ||
505 | user->ssp_inactivity_timeout = 5; | ||
506 | user->stp_max_occupancy_timeout = 5; | ||
507 | user->ssp_max_occupancy_timeout = 20; | ||
508 | user->no_outbound_task_timeout = 2; | ||
509 | } | ||
510 | |||
400 | static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) | 511 | static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) |
401 | { | 512 | { |
402 | struct isci_host *isci_host; | 513 | struct isci_orom *orom = to_pci_info(pdev)->orom; |
514 | struct sci_user_parameters sci_user_params; | ||
515 | u8 oem_version = ISCI_ROM_VER_1_0; | ||
516 | struct isci_host *ihost; | ||
403 | struct Scsi_Host *shost; | 517 | struct Scsi_Host *shost; |
404 | int err; | 518 | int err, i; |
405 | 519 | ||
406 | isci_host = devm_kzalloc(&pdev->dev, sizeof(*isci_host), GFP_KERNEL); | 520 | ihost = devm_kzalloc(&pdev->dev, sizeof(*ihost), GFP_KERNEL); |
407 | if (!isci_host) | 521 | if (!ihost) |
522 | return NULL; | ||
523 | |||
524 | ihost->pdev = pdev; | ||
525 | ihost->id = id; | ||
526 | spin_lock_init(&ihost->scic_lock); | ||
527 | init_waitqueue_head(&ihost->eventq); | ||
528 | ihost->sas_ha.dev = &ihost->pdev->dev; | ||
529 | ihost->sas_ha.lldd_ha = ihost; | ||
530 | tasklet_init(&ihost->completion_tasklet, | ||
531 | isci_host_completion_routine, (unsigned long)ihost); | ||
532 | |||
533 | /* validate module parameters */ | ||
534 | /* TODO: kill struct sci_user_parameters and reference directly */ | ||
535 | sci_oem_defaults(ihost); | ||
536 | isci_user_parameters_get(&sci_user_params); | ||
537 | if (sci_user_parameters_set(ihost, &sci_user_params)) { | ||
538 | dev_warn(&pdev->dev, | ||
539 | "%s: sci_user_parameters_set failed\n", __func__); | ||
540 | return NULL; | ||
541 | } | ||
542 | |||
543 | /* sanity check platform (or 'firmware') oem parameters */ | ||
544 | if (orom) { | ||
545 | if (id < 0 || id >= SCI_MAX_CONTROLLERS || id > orom->hdr.num_elements) { | ||
546 | dev_warn(&pdev->dev, "parsing firmware oem parameters failed\n"); | ||
547 | return NULL; | ||
548 | } | ||
549 | ihost->oem_parameters = orom->ctrl[id]; | ||
550 | oem_version = orom->hdr.version; | ||
551 | } | ||
552 | |||
553 | /* validate oem parameters (platform, firmware, or built-in defaults) */ | ||
554 | if (sci_oem_parameters_validate(&ihost->oem_parameters, oem_version)) { | ||
555 | dev_warn(&pdev->dev, "oem parameter validation failed\n"); | ||
408 | return NULL; | 556 | return NULL; |
557 | } | ||
558 | |||
559 | INIT_LIST_HEAD(&ihost->requests_to_complete); | ||
560 | INIT_LIST_HEAD(&ihost->requests_to_errorback); | ||
561 | for (i = 0; i < SCI_MAX_PORTS; i++) { | ||
562 | struct isci_port *iport = &ihost->ports[i]; | ||
563 | |||
564 | INIT_LIST_HEAD(&iport->remote_dev_list); | ||
565 | iport->isci_host = ihost; | ||
566 | } | ||
409 | 567 | ||
410 | isci_host->pdev = pdev; | 568 | for (i = 0; i < SCI_MAX_PHYS; i++) |
411 | isci_host->id = id; | 569 | isci_phy_init(&ihost->phys[i], ihost, i); |
570 | |||
571 | for (i = 0; i < SCI_MAX_REMOTE_DEVICES; i++) { | ||
572 | struct isci_remote_device *idev = &ihost->devices[i]; | ||
573 | |||
574 | INIT_LIST_HEAD(&idev->reqs_in_process); | ||
575 | INIT_LIST_HEAD(&idev->node); | ||
576 | } | ||
412 | 577 | ||
413 | shost = scsi_host_alloc(&isci_sht, sizeof(void *)); | 578 | shost = scsi_host_alloc(&isci_sht, sizeof(void *)); |
414 | if (!shost) | 579 | if (!shost) |
415 | return NULL; | 580 | return NULL; |
416 | isci_host->shost = shost; | 581 | ihost->shost = shost; |
417 | 582 | ||
418 | dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: " | 583 | dev_info(&pdev->dev, "%sSCU controller %d: phy 3-0 cables: " |
419 | "{%s, %s, %s, %s}\n", | 584 | "{%s, %s, %s, %s}\n", |
420 | (is_cable_select_overridden() ? "* " : ""), isci_host->id, | 585 | (is_cable_select_overridden() ? "* " : ""), ihost->id, |
421 | lookup_cable_names(decode_cable_selection(isci_host, 3)), | 586 | lookup_cable_names(decode_cable_selection(ihost, 3)), |
422 | lookup_cable_names(decode_cable_selection(isci_host, 2)), | 587 | lookup_cable_names(decode_cable_selection(ihost, 2)), |
423 | lookup_cable_names(decode_cable_selection(isci_host, 1)), | 588 | lookup_cable_names(decode_cable_selection(ihost, 1)), |
424 | lookup_cable_names(decode_cable_selection(isci_host, 0))); | 589 | lookup_cable_names(decode_cable_selection(ihost, 0))); |
425 | 590 | ||
426 | err = isci_host_init(isci_host); | 591 | err = isci_host_init(ihost); |
427 | if (err) | 592 | if (err) |
428 | goto err_shost; | 593 | goto err_shost; |
429 | 594 | ||
430 | SHOST_TO_SAS_HA(shost) = &isci_host->sas_ha; | 595 | SHOST_TO_SAS_HA(shost) = &ihost->sas_ha; |
431 | isci_host->sas_ha.core.shost = shost; | 596 | ihost->sas_ha.core.shost = shost; |
432 | shost->transportt = isci_transport_template; | 597 | shost->transportt = isci_transport_template; |
433 | 598 | ||
434 | shost->max_id = ~0; | 599 | shost->max_id = ~0; |
@@ -439,11 +604,11 @@ static struct isci_host *isci_host_alloc(struct pci_dev *pdev, int id) | |||
439 | if (err) | 604 | if (err) |
440 | goto err_shost; | 605 | goto err_shost; |
441 | 606 | ||
442 | err = isci_register_sas_ha(isci_host); | 607 | err = isci_register_sas_ha(ihost); |
443 | if (err) | 608 | if (err) |
444 | goto err_shost_remove; | 609 | goto err_shost_remove; |
445 | 610 | ||
446 | return isci_host; | 611 | return ihost; |
447 | 612 | ||
448 | err_shost_remove: | 613 | err_shost_remove: |
449 | scsi_remove_host(shost); | 614 | scsi_remove_host(shost); |