📄 megaraid_mbox.c
字号:
con_log(CL_ANN, (KERN_WARNING "megaraid mailbox: max commands per lun reset to %d\n", MBOX_MAX_SCSI_CMDS)); megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS; } // register as a PCI hot-plug driver module if ((rval = pci_module_init(&megaraid_pci_driver_g))) { con_log(CL_ANN, (KERN_WARNING "megaraid: could not register hotplug support.\n")); } return rval;}/** * megaraid_exit - driver unload entry point * * We simply unwrap the megaraid_init routine here */static void __exitmegaraid_exit(void){ con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n")); // unregister as PCI hotplug driver pci_unregister_driver(&megaraid_pci_driver_g); return;}/** * megaraid_probe_one - PCI hotplug entry point * @param pdev : handle to this controller's PCI configuration space * @param id : pci device id of the class of controllers * * This routine should be called whenever a new adapter is detected by the * PCI hotplug susbsytem. **/static int __devinitmegaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id){ adapter_t *adapter; // detected a new controller con_log(CL_ANN, (KERN_INFO "megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device)); con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn))); if (pci_enable_device(pdev)) { con_log(CL_ANN, (KERN_WARNING "megaraid: pci_enable_device failed\n")); return -ENODEV; } // Enable bus-mastering on this controller pci_set_master(pdev); // Allocate the per driver initialization structure adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL); if (adapter == NULL) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__)); goto out_probe_one; } memset(adapter, 0, sizeof(adapter_t)); // set up PCI related soft state and other pre-known parameters adapter->unique_id = pdev->bus->number << 8 | pdev->devfn; adapter->irq = pdev->irq; adapter->pdev = pdev; atomic_set(&adapter->being_detached, 0); // Setup the default DMA mask. This would be changed later on // depending on hardware capabilities if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFF) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: pci_set_dma_mask failed:%d\n", __LINE__)); goto out_free_adapter; } // Initialize the synchronization lock for kernel and LLD spin_lock_init(&adapter->lock); adapter->host_lock = &adapter->lock; // Initialize the command queues: the list of free SCBs and the list // of pending SCBs. INIT_LIST_HEAD(&adapter->kscb_pool); spin_lock_init(SCSI_FREE_LIST_LOCK(adapter)); INIT_LIST_HEAD(&adapter->pend_list); spin_lock_init(PENDING_LIST_LOCK(adapter)); INIT_LIST_HEAD(&adapter->completed_list); spin_lock_init(COMPLETED_LIST_LOCK(adapter)); // Start the mailbox based controller if (megaraid_init_mbox(adapter) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: maibox adapter did not initialize\n")); goto out_free_adapter; } // Register with LSI Common Management Module if (megaraid_cmm_register(adapter) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: could not register with management module\n")); goto out_fini_mbox; } // setup adapter handle in PCI soft state pci_set_drvdata(pdev, adapter); // attach with scsi mid-layer if (megaraid_io_attach(adapter) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n")); goto out_cmm_unreg; } return 0;out_cmm_unreg: pci_set_drvdata(pdev, NULL); megaraid_cmm_unregister(adapter);out_fini_mbox: megaraid_fini_mbox(adapter);out_free_adapter: kfree(adapter);out_probe_one: pci_disable_device(pdev); return -ENODEV;}/** * megaraid_detach_one - release the framework resources and call LLD release * routine * @param pdev : handle for our PCI cofiguration space * * This routine is called during driver unload. We free all the allocated * resources and call the corresponding LLD so that it can also release all * its resources. * * This routine is also called from the PCI hotplug system **/static voidmegaraid_detach_one(struct pci_dev *pdev){ adapter_t *adapter; struct Scsi_Host *host; // Start a rollback on this adapter adapter = pci_get_drvdata(pdev); if (!adapter) { con_log(CL_ANN, (KERN_CRIT "megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device)); return; } else { con_log(CL_ANN, (KERN_NOTICE "megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, pdev->subsystem_device)); } host = adapter->host; // do not allow any more requests from the management module for this // adapter. // FIXME: How do we account for the request which might still be // pending with us? atomic_set(&adapter->being_detached, 1); // detach from the IO sub-system megaraid_io_detach(adapter); // reset the device state in the PCI structure. We check this // condition when we enter here. If the device state is NULL, // that would mean the device has already been removed pci_set_drvdata(pdev, NULL); // Unregister from common management module // // FIXME: this must return success or failure for conditions if there // is a command pending with LLD or not. megaraid_cmm_unregister(adapter); // finalize the mailbox based controller and release all resources megaraid_fini_mbox(adapter); kfree(adapter); scsi_host_put(host); pci_disable_device(pdev); return;}/** * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA * @param device : generice driver model device * * Shutdown notification, perform flush cache */static voidmegaraid_mbox_shutdown(struct device *device){ adapter_t *adapter = pci_get_drvdata(to_pci_dev(device)); static int counter; if (!adapter) { con_log(CL_ANN, (KERN_WARNING "megaraid: null device in shutdown\n")); return; } // flush caches now con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...", counter++)); megaraid_mbox_flush_cache(adapter); con_log(CL_ANN, ("done\n"));}/** * megaraid_io_attach - attach a device with the IO subsystem * @param adapter : controller's soft state * * Attach this device with the IO subsystem **/static intmegaraid_io_attach(adapter_t *adapter){ struct Scsi_Host *host; // Initialize SCSI Host structure host = scsi_host_alloc(&megaraid_template_g, 8); if (!host) { con_log(CL_ANN, (KERN_WARNING "megaraid mbox: scsi_register failed\n")); return -1; } SCSIHOST2ADAP(host) = (caddr_t)adapter; adapter->host = host; // export the parameters required by the mid-layer scsi_assign_lock(host, adapter->host_lock); scsi_set_device(host, &adapter->pdev->dev); host->irq = adapter->irq; host->unique_id = adapter->unique_id; host->can_queue = adapter->max_cmds; host->this_id = adapter->init_id; host->sg_tablesize = adapter->sglen; host->max_sectors = adapter->max_sectors; host->cmd_per_lun = adapter->cmd_per_lun; host->max_channel = adapter->max_channel; host->max_id = adapter->max_target; host->max_lun = adapter->max_lun; // notify mid-layer about the new controller if (scsi_add_host(host, &adapter->pdev->dev)) { con_log(CL_ANN, (KERN_WARNING "megaraid mbox: scsi_add_host failed\n")); scsi_host_put(host); return -1; } scsi_scan_host(host); return 0;}/** * megaraid_io_detach - detach a device from the IO subsystem * @param adapter : controller's soft state * * Detach this device from the IO subsystem **/static voidmegaraid_io_detach(adapter_t *adapter){ struct Scsi_Host *host; con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n")); host = adapter->host; scsi_remove_host(host); return;}/* * START: Mailbox Low Level Driver * * This is section specific to the single mailbox based controllers *//** * megaraid_init_mbox - initialize controller * @param adapter - our soft state * * . Allocate 16-byte aligned mailbox memory for firmware handshake * . Allocate controller's memory resources * . Find out all initialization data * . Allocate memory required for all the commands * . Use internal library of FW routines, build up complete soft state */static int __initmegaraid_init_mbox(adapter_t *adapter){ struct pci_dev *pdev; mraid_device_t *raid_dev; int i; adapter->ito = MBOX_TIMEOUT; pdev = adapter->pdev; /* * Allocate and initialize the init data structure for mailbox * controllers */ raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL); if (raid_dev == NULL) return -1; memset(raid_dev, 0, sizeof(mraid_device_t)); /* * Attach the adapter soft state to raid device soft state */ adapter->raid_device = (caddr_t)raid_dev; raid_dev->fast_load = megaraid_fast_load; // our baseport raid_dev->baseport = pci_resource_start(pdev, 0); if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: mem region busy\n")); goto out_free_raid_dev; } raid_dev->baseaddr = ioremap_nocache(raid_dev->baseport, 128); if (!raid_dev->baseaddr) { con_log(CL_ANN, (KERN_WARNING "megaraid: could not map hba memory\n") ); goto out_release_regions; } // // Setup the rest of the soft state using the library of FW routines // // request IRQ and register the interrupt service routine if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid", adapter)) { con_log(CL_ANN, (KERN_WARNING "megaraid: Couldn't register IRQ %d!\n", adapter->irq)); goto out_iounmap; } // initialize the mutual exclusion lock for the mailbox spin_lock_init(&raid_dev->mailbox_lock); // allocate memory required for commands if (megaraid_alloc_cmd_packets(adapter) != 0) { goto out_free_irq; } // Product info if (megaraid_mbox_product_info(adapter) != 0) { goto out_alloc_cmds; } // Do we support extended CDBs adapter->max_cdb_sz = 10; if (megaraid_mbox_extended_cdb(adapter) == 0) { adapter->max_cdb_sz = 16; } /* * Do we support cluster environment, if we do, what is the initiator * id. * NOTE: In a non-cluster aware firmware environment, the LLD should * return 7 as initiator id. */ adapter->ha = 0; adapter->init_id = -1; if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) { adapter->ha = 1; } /* * Prepare the device ids array to have the mapping between the kernel * device address and megaraid device address. * We export the physical devices on their actual addresses. The * logical drives are exported on a virtual SCSI channel */ megaraid_mbox_setup_device_map(adapter); // If the firmware supports random deletion, update the device id map if (megaraid_mbox_support_random_del(adapter)) { // Change the logical drives numbers in device_ids array one // slot in device_ids is reserved for target id, that's why // "<=" below for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) { adapter->device_ids[adapter->max_channel][i] += 0x80; } adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF; raid_dev->random_del_supported = 1; } /* * find out the maximum number of scatter-gather elements supported by * this firmware */ adapter->sglen = megaraid_mbox_get_max_sg(adapter); // enumerate RAID and SCSI channels so that all devices on SCSI // channels can later be exported, including disk devices megaraid_mbox_enum_raid_scsi(adapter); /* * Other parameters required by upper layer * * maximum number of sectors per IO command */ adapter->max_sectors = megaraid_max_sectors; /* * number of queued commands per LUN. */ adapter->cmd_per_lun = megaraid_cmd_per_lun; /* * Allocate resources required to issue FW calls, when sysfs is * accessed */ if (megaraid_sysfs_alloc_resources(adapter) != 0) { goto out_alloc_cmds; } // Set the DMA mask to 64-bit. All supported controllers as capable of // DMA in this range if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFFFFFFFFFFULL) != 0) { con_log(CL_ANN, (KERN_WARNING "megaraid: could not set DMA mask for 64-bit.\n")); goto out_free_sysfs_res; } // setup tasklet for DPC tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc, (unsigned long)adapter); con_log(CL_DLEVEL1, (KERN_INFO "megaraid mbox hba successfully initialized\n")); return 0;out_free_sysfs_res: megaraid_sysfs_free_resources(adapter);out_alloc_cmds: megaraid_free_cmd_packets(adapter);out_free_irq: free_irq(adapter->irq, adapter);out_iounmap: iounmap(raid_dev->baseaddr);out_release_regions: pci_release_regions(pdev);out_free_raid_dev: kfree(raid_dev);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -