ql4_os.c
来自「linux 内核源代码」· C语言 代码 · 共 1,732 行 · 第 1/4 页
C
1,732 行
/* * QLogic iSCSI HBA Driver * Copyright (c) 2003-2006 QLogic Corporation * * See LICENSE.qla4xxx for copyright and licensing details. */#include <linux/moduleparam.h>#include <scsi/scsi_tcq.h>#include <scsi/scsicam.h>#include "ql4_def.h"#include "ql4_version.h"#include "ql4_glbl.h"#include "ql4_dbg.h"#include "ql4_inline.h"/* * Driver version */static char qla4xxx_version_str[40];/* * SRB allocation cache */static struct kmem_cache *srb_cachep;/* * Module parameter information and variables */int ql4xdiscoverywait = 60;module_param(ql4xdiscoverywait, int, S_IRUGO | S_IRUSR);MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time");int ql4xdontresethba = 0;module_param(ql4xdontresethba, int, S_IRUGO | S_IRUSR);MODULE_PARM_DESC(ql4xdontresethba, "Dont reset the HBA when the driver gets 0x8002 AEN " " default it will reset hba :0" " set to 1 to avoid resetting HBA");int ql4xextended_error_logging = 0; /* 0 = off, 1 = log errors */module_param(ql4xextended_error_logging, int, S_IRUGO | S_IRUSR);MODULE_PARM_DESC(ql4xextended_error_logging, "Option to enable extended error logging, " "Default is 0 - no logging, 1 - debug logging");int ql4_mod_unload = 0;/* * SCSI host template entry points */static void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);/* * iSCSI template entry points */static int qla4xxx_tgt_dscvr(struct Scsi_Host *shost, enum iscsi_tgt_dscvr type, uint32_t enable, struct sockaddr *dst_addr);static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, enum iscsi_param param, char *buf);static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, enum iscsi_param param, char *buf);static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf);static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag);static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);/* * SCSI host template entry points */static int qla4xxx_queuecommand(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *));static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);static int qla4xxx_slave_alloc(struct scsi_device *device);static int qla4xxx_slave_configure(struct scsi_device *device);static void qla4xxx_slave_destroy(struct scsi_device *sdev);static struct scsi_host_template qla4xxx_driver_template = { .module = THIS_MODULE, .name = DRIVER_NAME, .proc_name = DRIVER_NAME, .queuecommand = qla4xxx_queuecommand, .eh_device_reset_handler = qla4xxx_eh_device_reset, .eh_host_reset_handler = qla4xxx_eh_host_reset, .slave_configure = qla4xxx_slave_configure, .slave_alloc = qla4xxx_slave_alloc, .slave_destroy = qla4xxx_slave_destroy, .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, .use_sg_chaining = ENABLE_SG_CHAINING, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF,};static struct iscsi_transport qla4xxx_iscsi_transport = { .owner = THIS_MODULE, .name = DRIVER_NAME, .caps = CAP_FW_DB | CAP_SENDTARGETS_OFFLOAD | CAP_DATA_PATH_OFFLOAD, .param_mask = ISCSI_CONN_PORT | ISCSI_CONN_ADDRESS | ISCSI_TARGET_NAME | ISCSI_TPGT, .host_param_mask = ISCSI_HOST_HWADDRESS | ISCSI_HOST_IPADDRESS | ISCSI_HOST_INITIATOR_NAME, .sessiondata_size = sizeof(struct ddb_entry), .host_template = &qla4xxx_driver_template, .tgt_dscvr = qla4xxx_tgt_dscvr, .get_conn_param = qla4xxx_conn_get_param, .get_session_param = qla4xxx_sess_get_param, .get_host_param = qla4xxx_host_get_param, .start_conn = qla4xxx_conn_start, .stop_conn = qla4xxx_conn_stop, .session_recovery_timedout = qla4xxx_recovery_timedout,};static struct scsi_transport_template *qla4xxx_scsi_transport;static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session){ struct ddb_entry *ddb_entry = session->dd_data; struct scsi_qla_host *ha = ddb_entry->ha; DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) " "secs exhausted, marking device DEAD.\n", ha->host_no, __func__, ddb_entry->fw_ddb_index, ha->port_down_retry_count)); atomic_set(&ddb_entry->state, DDB_STATE_DEAD); DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = " "0x%lx\n", ha->host_no, __func__, ha->dpc_flags)); queue_work(ha->dpc_thread, &ha->dpc_work);}static int qla4xxx_conn_start(struct iscsi_cls_conn *conn){ struct iscsi_cls_session *session; struct ddb_entry *ddb_entry; session = iscsi_dev_to_session(conn->dev.parent); ddb_entry = session->dd_data; DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n", ddb_entry->ha->host_no, __func__, ddb_entry->fw_ddb_index)); iscsi_unblock_session(session); return 0;}static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag){ struct iscsi_cls_session *session; struct ddb_entry *ddb_entry; session = iscsi_dev_to_session(conn->dev.parent); ddb_entry = session->dd_data; DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n", ddb_entry->ha->host_no, __func__, ddb_entry->fw_ddb_index)); if (flag == STOP_CONN_RECOVER) iscsi_block_session(session); else printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);}static ssize_t format_addr(char *buf, const unsigned char *addr, int len){ int i; char *cp = buf; for (i = 0; i < len; i++) cp += sprintf(cp, "%02x%c", addr[i], i == (len - 1) ? '\n' : ':'); return cp - buf;}static int qla4xxx_host_get_param(struct Scsi_Host *shost, enum iscsi_host_param param, char *buf){ struct scsi_qla_host *ha = to_qla_host(shost); int len; switch (param) { case ISCSI_HOST_PARAM_HWADDRESS: len = format_addr(buf, ha->my_mac, MAC_ADDR_LEN); break; case ISCSI_HOST_PARAM_IPADDRESS: len = sprintf(buf, "%d.%d.%d.%d\n", ha->ip_address[0], ha->ip_address[1], ha->ip_address[2], ha->ip_address[3]); break; case ISCSI_HOST_PARAM_INITIATOR_NAME: len = sprintf(buf, "%s\n", ha->name_string); break; default: return -ENOSYS; } return len;}static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess, enum iscsi_param param, char *buf){ struct ddb_entry *ddb_entry = sess->dd_data; int len; switch (param) { case ISCSI_PARAM_TARGET_NAME: len = snprintf(buf, PAGE_SIZE - 1, "%s\n", ddb_entry->iscsi_name); break; case ISCSI_PARAM_TPGT: len = sprintf(buf, "%u\n", ddb_entry->tpgt); break; default: return -ENOSYS; } return len;}static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, enum iscsi_param param, char *buf){ struct iscsi_cls_session *session; struct ddb_entry *ddb_entry; int len; session = iscsi_dev_to_session(conn->dev.parent); ddb_entry = session->dd_data; switch (param) { case ISCSI_PARAM_CONN_PORT: len = sprintf(buf, "%hu\n", ddb_entry->port); break; case ISCSI_PARAM_CONN_ADDRESS: /* TODO: what are the ipv6 bits */ len = sprintf(buf, "%u.%u.%u.%u\n", NIPQUAD(ddb_entry->ip_addr)); break; default: return -ENOSYS; } return len;}static int qla4xxx_tgt_dscvr(struct Scsi_Host *shost, enum iscsi_tgt_dscvr type, uint32_t enable, struct sockaddr *dst_addr){ struct scsi_qla_host *ha; struct sockaddr_in *addr; struct sockaddr_in6 *addr6; int ret = 0; ha = (struct scsi_qla_host *) shost->hostdata; switch (type) { case ISCSI_TGT_DSCVR_SEND_TARGETS: if (dst_addr->sa_family == AF_INET) { addr = (struct sockaddr_in *)dst_addr; if (qla4xxx_send_tgts(ha, (char *)&addr->sin_addr, addr->sin_port) != QLA_SUCCESS) ret = -EIO; } else if (dst_addr->sa_family == AF_INET6) { /* * TODO: fix qla4xxx_send_tgts */ addr6 = (struct sockaddr_in6 *)dst_addr; if (qla4xxx_send_tgts(ha, (char *)&addr6->sin6_addr, addr6->sin6_port) != QLA_SUCCESS) ret = -EIO; } else ret = -ENOSYS; break; default: ret = -ENOSYS; } return ret;}void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry){ if (!ddb_entry->sess) return; if (ddb_entry->conn) { iscsi_if_destroy_session_done(ddb_entry->conn); iscsi_destroy_conn(ddb_entry->conn); iscsi_remove_session(ddb_entry->sess); } iscsi_free_session(ddb_entry->sess);}int qla4xxx_add_sess(struct ddb_entry *ddb_entry){ int err; err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index); if (err) { DEBUG2(printk(KERN_ERR "Could not add session.\n")); return err; } ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0); if (!ddb_entry->conn) { iscsi_remove_session(ddb_entry->sess); DEBUG2(printk(KERN_ERR "Could not add connection.\n")); return -ENOMEM; } ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count; iscsi_if_create_session_done(ddb_entry->conn); return 0;}struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha){ struct ddb_entry *ddb_entry; struct iscsi_cls_session *sess; sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport); if (!sess) return NULL; ddb_entry = sess->dd_data; memset(ddb_entry, 0, sizeof(*ddb_entry)); ddb_entry->ha = ha; ddb_entry->sess = sess; return ddb_entry;}/* * Timer routines */static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func, unsigned long interval){ DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n", __func__, ha->host->host_no)); init_timer(&ha->timer); ha->timer.expires = jiffies + interval * HZ; ha->timer.data = (unsigned long)ha; ha->timer.function = (void (*)(unsigned long))func; add_timer(&ha->timer); ha->timer_active = 1;}static void qla4xxx_stop_timer(struct scsi_qla_host *ha){ del_timer_sync(&ha->timer); ha->timer_active = 0;}/*** * qla4xxx_mark_device_missing - mark a device as missing. * @ha: Pointer to host adapter structure. * @ddb_entry: Pointer to device database entry * * This routine marks a device missing and resets the relogin retry count. **/void qla4xxx_mark_device_missing(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry){ atomic_set(&ddb_entry->state, DDB_STATE_MISSING); DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n", ha->host_no, ddb_entry->bus, ddb_entry->target, ddb_entry->fw_ddb_index)); iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);}static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha, struct ddb_entry *ddb_entry, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)){ struct srb *srb; srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC); if (!srb) return srb; atomic_set(&srb->ref_count, 1); srb->ha = ha; srb->ddb = ddb_entry; srb->cmd = cmd; srb->flags = 0; cmd->SCp.ptr = (void *)srb; cmd->scsi_done = done; return srb;}static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb){ struct scsi_cmnd *cmd = srb->cmd; if (srb->flags & SRB_DMA_VALID) { scsi_dma_unmap(cmd); srb->flags &= ~SRB_DMA_VALID; } cmd->SCp.ptr = NULL;}void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb){ struct scsi_cmnd *cmd = srb->cmd; qla4xxx_srb_free_dma(ha, srb); mempool_free(srb, ha->srb_mempool); cmd->scsi_done(cmd);}/** * qla4xxx_queuecommand - scsi layer issues scsi command to driver. * @cmd: Pointer to Linux's SCSI command structure * @done_fn: Function that the driver calls to notify the SCSI mid-layer
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?