📄 megaraid_mbox.c
字号:
goto out_free_adapter; } // Initialize the synchronization lock for kernel and LLD spin_lock_init(&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 pci_dev *pdev){ adapter_t *adapter = pci_get_drvdata(pdev); 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; 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, DMA_64BIT_MASK) != 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); return -1;}/** * megaraid_fini_mbox - undo controller initialization * @param adapter : our soft state */static voidmegaraid_fini_mbox(adapter_t *adapter){ mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); // flush all caches megaraid_mbox_flush_cache(adapter); tasklet_kill(&adapter->dpc_h); megaraid_sysfs_free_resources(adapter); megaraid_free_cmd_packets(adapter); free_irq(adapter->irq, adapter); iounmap(raid_dev->baseaddr); pci_release_regions(adapter->pdev); kfree(raid_dev); return;}/** * megaraid_alloc_cmd_packets - allocate shared mailbox * @param adapter : soft state of the raid controller * * Allocate and align the shared mailbox. This maibox is used to issue * all the commands. For IO based controllers, the mailbox is also regsitered * with the FW. Allocate memory for all commands as well. * This is our big allocator */static intmegaraid_alloc_cmd_packets(adapter_t *adapter){ mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter); struct pci_dev *pdev; unsigned long align; scb_t *scb; mbox_ccb_t *ccb; struct mraid_pci_blk *epthru_pci_blk; struct mraid_pci_blk *sg_pci_blk; struct mraid_pci_blk *mbox_pci_blk; int i; pdev = adapter->pdev; /* * Setup the mailbox * Allocate the common 16-byte aligned memory for the handshake * mailbox. */ raid_dev->una_mbox64 = pci_alloc_consistent(adapter->pdev, sizeof(mbox64_t), &raid_dev->una_mbox64_dma); if (!raid_dev->una_mbox64) { con_log(CL_ANN, (KERN_WARNING "megaraid: out of memory, %s %d\n", __FUNCTION__, __LINE__)); return -1; } memset(raid_dev->una_mbox64, 0, sizeof(mbox64_t)); /* * Align the mailbox at 16-byte boundary */ raid_dev->mbox = &raid_dev->una_mbox64->mbox32; raid_dev->mbox = (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) & (~0UL ^ 0xFUL)); raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8); align = ((void *)raid_dev->mbox - ((void *)&raid_dev->una_mbox64->mbox32)); raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 + align; // Allocate memory for commands issued internally adapter->ibuf = pci_alloc_consistent(pdev, MBOX_IBUF_SIZE, &adapter->ibuf_dma_h); if (!adapter->ibuf) { con_log(CL_ANN, (KERN_WARNING
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -