📄 qla_cfg.c
字号:
/****************************************************************************** * QLOGIC LINUX SOFTWARE * * QLogic ISP2x00 device driver for Linux 2.4.x * Copyright (C) 2002 Qlogic Corporation * (www.qlogic.com) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * ******************************************************************************//* * QLogic ISP2x00 Multi-path LUN Support Driver * */#include "qlfo.h"#include "qla_cfg.h"#include "qla_gbl.h"#if defined(LINUX)#include "qla_cfgln.c"#endif/* * Local Function Prototypes. */static mp_path_t * qla2x00_select_next_path(mp_host_t *host, mp_device_t *dp, uint8_t);static uint32_t qla2x00_add_portname_to_mp_dev(mp_device_t *, uint8_t *);static mp_device_t * qla2x00_allocate_mp_dev(uint8_t *, uint8_t *);static mp_path_t * qla2x00_allocate_path(mp_host_t *host, uint16_t path_id, fc_port_t *port, uint16_t dev_id);static mp_host_t * qla2x00_find_host_by_name(uint8_t *);static mp_device_t * qla2x00_find_or_allocate_mp_dev (mp_host_t *, uint16_t, fc_port_t *);static mp_path_t * qla2x00_find_or_allocate_path(mp_host_t *, mp_device_t *, uint16_t, fc_port_t *);static uint32_t qla2x00_send_failover_notify(mp_device_t *, uint8_t lun, mp_path_t *new_path, mp_path_t *old_path);static BOOL qla2x00_update_mp_host( mp_host_t *);static uint32_t qla2x00_update_mp_tree (void);static fc_lun_t *qla2x00_find_matching_lun(uint8_t , mp_path_t *);static mp_path_t *qla2x00_find_path_by_id(mp_device_t *, uint8_t );static mp_device_t *qla2x00_find_mp_dev_by_id(mp_host_t *, uint8_t );static mp_device_t *qla2x00_find_mp_dev_by_name(mp_host_t *, uint8_t *);static BOOL qla2x00_is_ww_name_zero(uint8_t *);static void qla2x00_add_path(mp_path_list_t *, mp_path_t *);static BOOL qla2x00_is_portname_in_device(mp_device_t *, uint8_t *);static void qla2x00_failback_luns( mp_host_t *);static void qla2x00_failback_single_lun( mp_device_t *dp, uint8_t lun, uint8_t new);static void qla2x00_setup_new_path( mp_device_t *, mp_path_t *);static void qla2x00_map_os_targets(mp_host_t *);static void qla2x00_map_os_luns(mp_host_t *, mp_device_t *, uint16_t );mp_host_t * qla2x00_cfg_find_host(scsi_qla_host_t *ha);static mp_path_list_t * qla2x00_allocate_path_list( void );static uint32_tqla2x00_cfg_register_failover_lun(mp_device_t *,srb_t *, fc_lun_t *);static voidqla2x00_map_a_oslun(mp_host_t *, mp_device_t *, uint16_t , uint16_t );static mp_path_t *qla2x00_get_visible_path(mp_device_t *dp);/* * Global data items */mp_host_t *mp_hosts_base = NULL;BOOL mp_config_required = FALSE;static int mp_num_hosts = 0;static BOOL mp_initialized = FALSE;/* * ENTRY ROUTINES *//* * qla2x00_cfg_init * Initialize configuration structures to handle an instance of * an HBA, QLA2x000 card. * * Input: * ha = adapter state pointer. * * Returns: * qla2x00 local function return status code. * * Context: * Kernel context. */intqla2x00_cfg_init(scsi_qla_host_t *ha){ int rval; ENTER("qla2x00_cfg_init"); set_bit(CFG_ACTIVE, &ha->cfg_flags); if (!mp_initialized) { /* First HBA, initialize the failover global properties */ qla2x00_fo_init_params(ha); /* If the user specified a device configuration then * it is use as the configuration. Otherwise, we wait * for path discovery. */ if ( mp_config_required ) qla2x00_cfg_build_path_tree(ha); } rval = qla2x00_cfg_path_discovery(ha); clear_bit(CFG_ACTIVE, &ha->cfg_flags); LEAVE("qla2x00_cfg_init"); return rval;}/* * qla2x00_cfg_path_discovery * Discover the path configuration from the device configuration * for the specified host adapter and build the path search tree. * This function is called after the lower level driver has * completed its port and lun discovery. * * Input: * ha = adapter state pointer. * * Returns: * qla2x00 local function return status code. * * Context: * Kernel context. */intqla2x00_cfg_path_discovery(scsi_qla_host_t *ha){ int rval = QLA2X00_SUCCESS; mp_host_t *host; uint8_t *name; ENTER("qla2x00_cfg_path_discovery"); name = &ha->init_cb->node_name[0]; set_bit(CFG_ACTIVE, &ha->cfg_flags); /* Initialize the path tree for this adapter */ host = qla2x00_find_host_by_name(name); if ( mp_config_required ) { if (host == NULL ) { DEBUG4(printk("cfg_path_discovery: host not found, " "node name = " "%02x%02x%02x%02x%02x%02x%02x%02x\n", name[0], name[1], name[2], name[3], name[4], name[5], name[6], name[7]);) rval = QLA2X00_FUNCTION_FAILED; } else if (ha->instance != host->instance) { DEBUG4(printk("cfg_path_discovery: host instance " "don't match - instance=%ld.\n", ha->instance);) rval = QLA2X00_FUNCTION_FAILED; } } else if ( host == NULL ) { /* New host adapter so allocate it */ if ( (host = qla2x00_alloc_host(ha)) == NULL ) { printk(KERN_INFO "qla2x00(%d): Couldn't allocate " "host - ha = %p.\n", (int)ha->instance, ha); rval = QLA2X00_FUNCTION_FAILED; } } /* Fill in information about host */ if (host != NULL ) { host->flags |= MP_HOST_FLAG_NEEDS_UPDATE; host->fcport = ha->fcport; /* Check if multipath is enabled */ if (!qla2x00_update_mp_host(host)) { rval = QLA2X00_FUNCTION_FAILED; } } if (rval != QLA2X00_SUCCESS) { /* EMPTY */ DEBUG4(printk("qla2x00_path_discovery: Exiting FAILED\n");) } else { LEAVE("qla2x00_cfg_path_discovery"); } clear_bit(CFG_ACTIVE, &ha->cfg_flags); return rval;}/* * qla2x00_cfg_event_notifiy * Callback for host driver to notify us of configuration changes. * * Input: * ha = adapter state pointer. * i_type = event type * * Returns: * * Context: * Kernel context. */intqla2x00_cfg_event_notify(scsi_qla_host_t *ha, uint32_t i_type){ mp_host_t *host; /* host adapter pointer */ ENTER("qla2x00_cfg_event_notify"); set_bit(CFG_ACTIVE, &ha->cfg_flags); switch (i_type) { case MP_NOTIFY_RESET_DETECTED: DEBUG(printk("scsi%ld: MP_NOTIFY_RESET_DETECTED " "- no action\n", ha->host_no);) break; case MP_NOTIFY_PWR_LOSS: DEBUG(printk("scsi%ld: MP_NOTIFY_PWR_LOSS - " "update tree\n", ha->host_no);) /* * Update our path tree in case we are * losing the adapter */ qla2x00_update_mp_tree(); /* Free our resources for adapter */ break; case MP_NOTIFY_LOOP_UP: DEBUG(printk("scsi%ld: MP_NOTIFY_LOOP_UP - " "update host tree\n", ha->host_no);) /* Adapter is back up with new configuration */ if ((host = qla2x00_cfg_find_host(ha)) != NULL) { host->flags |= MP_HOST_FLAG_NEEDS_UPDATE; host->fcport = ha->fcport; qla2x00_update_mp_tree(); } break; case MP_NOTIFY_LOOP_DOWN: case MP_NOTIFY_BUS_RESET: DEBUG(printk("scsi%ld: MP_NOTIFY_OTHERS - " "no action\n", ha->host_no);) break; default: break; } clear_bit(CFG_ACTIVE, &ha->cfg_flags); LEAVE("qla2x00_cfg_event_notify"); return QLA2X00_SUCCESS;}/* * qla2x00_cfg_failover * A problem has been detected with the current path for this * lun. Select the next available path as the current path * for this device. * * Inputs: * ha = pointer to host adapter * fp - pointer to failed fc_lun (failback lun) * tgt - pointer to target * * Returns: * pointer to new fc_lun_t, or NULL if failover fails. */fc_lun_t *qla2x00_cfg_failover(scsi_qla_host_t *ha, fc_lun_t *fp, os_tgt_t *tgt, srb_t *sp){ mp_host_t *host; /* host adapter pointer */ mp_device_t *dp; /* virtual device pointer */ mp_path_t *new_path; /* new path pointer */ fc_lun_t *new_fp = NULL; ENTER("qla2x00_cfg_failover"); set_bit(CFG_ACTIVE, &ha->cfg_flags); if ((host = qla2x00_cfg_find_host(ha)) != NULL) { if ((dp = qla2x00_find_mp_dev_by_name( host, tgt->fc_name)) != NULL ) { DEBUG3(printk("qla2x00_cfg_failover: dp = %p\n", dp);) /* * Point at the next path in the path list if there is * one, and if it hasn't already been failed over by * another I/O. If there is only one path continuer * to point at it. */ new_path = qla2x00_select_next_path(host, dp, fp->lun); DEBUG3(printk("cfg_failover: new path @ %p\n", new_path);) new_fp = qla2x00_find_matching_lun(fp->lun, new_path); DEBUG3(printk("cfg_failover: new fp lun @ %p\n", new_fp);) qla2x00_cfg_register_failover_lun(dp, sp, new_fp); } else { printk(KERN_INFO "qla2x00(%d): Couldn't find device " "to failover\n", host->instance); } } clear_bit(CFG_ACTIVE, &ha->cfg_flags); LEAVE("qla2x00_cfg_failover"); return new_fp;}/* * IOCTL support */#define CFG_IOCTL#if defined(CFG_IOCTL)/* * qla2x00_cfg_get_paths * Get list of paths EXT_FO_GET_PATHS. * * Input: * ha = pointer to adapter * bp = pointer to buffer * cmd = Pointer to kernel copy of EXT_IOCTL. * * Return; * 0 on success or errno. * * Context: * Kernel context. */uint32_tqla2x00_cfg_get_paths(EXT_IOCTL *cmd, FO_GET_PATHS *bp, int mode){ FO_PATHS_INFO *paths, *u_paths; FO_PATH_ENTRY *entry; EXT_DEST_ADDR *sap = &bp->HbaAddr; mp_host_t *host; /* host adapter pointer */ mp_device_t *dp; /* virtual device pointer */ mp_path_t *path; /* path pointer */ mp_path_list_t *path_list; /* path list pointer */ int cnt; uint32_t rval = 0; scsi_qla_host_t *ha; u_paths = (FO_PATHS_INFO *) cmd->ResponseAdr; ha = qla2x00_get_hba((int)bp->HbaInstance); if ((host = qla2x00_cfg_find_host(ha)) == NULL) { cmd->Status = EXT_STATUS_DEV_NOT_FOUND; cmd->DetailStatus = EXT_DSTATUS_HBA_INST; DEBUG4(printk("qla2x00_get_paths: cannot find target (%ld)\n", ha->instance);) return ENODEV; } if ((paths = (FO_PATHS_INFO *)kmem_zalloc(sizeof(FO_PATHS_INFO), GFP_ATOMIC,20)) == NULL) { DEBUG4(printk("qla_cfg_get_paths: failed to allocate memory " "of size (%d)\n", (int)sizeof(FO_PATHS_INFO));) return 1; } /* Scan for mp_dev by nodename *ONLY* */ if (sap->DestType != EXT_DEF_DESTTYPE_WWNN) { cmd->Status = EXT_STATUS_INVALID_PARAM; cmd->DetailStatus = EXT_DSTATUS_TARGET; rval = ENODEV; DEBUG4(printk("qla2x00_cfg_get_paths: target ca be accessed " "by NodeName only.");) } else if ((dp = qla2x00_find_mp_dev_by_name(host, sap->DestAddr.WWNN)) != NULL) { path_list = dp->path_list; paths->HbaInstance = bp->HbaInstance; paths->PathCount = path_list->path_cnt; paths->VisiblePathIndex = path_list->visible; /* copy current paths */ memcpy(paths->CurrentPathIndex, path_list->current_path, sizeof(paths->CurrentPathIndex)); path = path_list->last; for (cnt = 0; cnt < path_list->path_cnt; cnt++) { entry = &(paths->PathEntry[path->id]); entry->Visible = (path->id == path_list->visible); entry->HbaInstance = path->host->instance; memcpy(entry->PortName, path->portname, EXT_DEF_WWP_NAME_SIZE); path = path->next; } /* copy data to user */ copy_to_user(&u_paths->PathCount, &paths->PathCount, 4); copy_to_user(&u_paths->CurrentPathIndex, &paths->CurrentPathIndex, sizeof(paths->CurrentPathIndex)); copy_to_user(&u_paths->PathEntry, &paths->PathEntry, sizeof(paths->PathEntry)); } else { cmd->Status = EXT_STATUS_DEV_NOT_FOUND; cmd->DetailStatus = EXT_DSTATUS_TARGET; DEBUG4(printk("qla2x00_cfg_get_paths: cannot find device " "(%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x)\n.", sap->DestAddr.WWNN[0], sap->DestAddr.WWNN[1], sap->DestAddr.WWNN[2], sap->DestAddr.WWNN[3], sap->DestAddr.WWNN[4], sap->DestAddr.WWNN[5], sap->DestAddr.WWNN[6], sap->DestAddr.WWNN[7]);) rval = ENODEV; } KMEM_FREE(paths, sizeof(paths)); return rval;}/* * qla2x00_cfg_set_current_path * Set the current failover path EXT_FO_GET_PATHS IOCTL call. * * Input: * ha = pointer to adapter * bp = pointer to buffer * cmd = Pointer to kernel copy of EXT_IOCTL. * * Return; * 0 on success or errno. * * Context: * Kernel context. */intqla2x00_cfg_set_current_path(EXT_IOCTL *cmd, FO_SET_CURRENT_PATH *bp, int mode ){ uint8_t orig_id, new_id; mp_host_t *host, *new_host; mp_device_t *dp; mp_path_list_t *path_list; EXT_DEST_ADDR *sap = &bp->HbaAddr; uint32_t rval = 0; scsi_qla_host_t *ha; mp_path_t *new_path, *old_path; /* First find the adapter with the instance number. */ ha = qla2x00_get_hba((int)bp->HbaInstance); if ((host = qla2x00_cfg_find_host(ha)) != NULL) { set_bit(CFG_ACTIVE, &ha->cfg_flags); sap = &bp->HbaAddr; /* Scan for mp_dev by nodename *ONLY* */ if (sap->DestType != EXT_DEF_DESTTYPE_WWNN) { cmd->Status = EXT_STATUS_DEV_NOT_FOUND; cmd->DetailStatus = EXT_DSTATUS_TARGET; rval = ENODEV; DEBUG4(printk("qla2x00_cfg_set_current_path: " "target ca be accessed by " "NodeName only.");) } else if ((dp = qla2x00_find_mp_dev_by_name( host, sap->DestAddr.WWNN)) != NULL) { path_list = dp->path_list; if (bp->NewCurrentPathIndex < MAX_PATHS_PER_DEVICE && sap->Lun < MAX_LUNS && bp->NewCurrentPathIndex < path_list->path_cnt) { orig_id = path_list->current_path[sap->Lun]; DEBUG(printk("qla2x00_set_current_path: " "dev no %d, lun %d, " "newindex %d, oldindex %d " "nn=%02x%02x%02x%02x%02x%02x%02x%02x\n", dp->dev_id, sap->Lun, bp->NewCurrentPathIndex, orig_id, host->nodename[0], host->nodename[1], host->nodename[2], host->nodename[3], host->nodename[4], host->nodename[5], host->nodename[6], host->nodename[7]);) if (bp->NewCurrentPathIndex != orig_id) { /* Acquire the update spinlock. */ /* Set the new current path. */ new_id = path_list->
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -