📄 qla_rscn.c
字号:
/* * QLogic Fibre Channel HBA Driver * Copyright (c) 2003-2005 QLogic Corporation * * See LICENSE.qla2xxx for copyright and licensing details. */#include "qla_def.h"#include <scsi/scsi_transport_fc.h>/** * IO descriptor handle definitions. * * Signature form: * * |31------28|27-------------------12|11-------0| * | Type | Rolling Signature | Index | * |----------|-----------------------|----------| * **/#define HDL_TYPE_SCSI 0#define HDL_TYPE_ASYNC_IOCB 0x0A#define HDL_INDEX_BITS 12#define HDL_ITER_BITS 16#define HDL_TYPE_BITS 4#define HDL_INDEX_MASK ((1UL << HDL_INDEX_BITS) - 1)#define HDL_ITER_MASK ((1UL << HDL_ITER_BITS) - 1)#define HDL_TYPE_MASK ((1UL << HDL_TYPE_BITS) - 1)#define HDL_INDEX_SHIFT 0#define HDL_ITER_SHIFT (HDL_INDEX_SHIFT + HDL_INDEX_BITS)#define HDL_TYPE_SHIFT (HDL_ITER_SHIFT + HDL_ITER_BITS)/* Local Prototypes. */static inline uint32_t qla2x00_to_handle(uint16_t, uint16_t, uint16_t);static inline uint16_t qla2x00_handle_to_idx(uint32_t);static inline uint32_t qla2x00_iodesc_to_handle(struct io_descriptor *);static inline struct io_descriptor *qla2x00_handle_to_iodesc(scsi_qla_host_t *, uint32_t);static inline struct io_descriptor *qla2x00_alloc_iodesc(scsi_qla_host_t *);static inline void qla2x00_free_iodesc(struct io_descriptor *);static inline void qla2x00_init_io_descriptors(scsi_qla_host_t *);static void qla2x00_iodesc_timeout(unsigned long);static inline void qla2x00_add_iodesc_timer(struct io_descriptor *);static inline void qla2x00_remove_iodesc_timer(struct io_descriptor *);static inline void qla2x00_update_login_fcport(scsi_qla_host_t *, struct mbx_entry *, fc_port_t *);static int qla2x00_send_abort_iocb(scsi_qla_host_t *, struct io_descriptor *, uint32_t, int);static int qla2x00_send_abort_iocb_cb(scsi_qla_host_t *, struct io_descriptor *, struct mbx_entry *);static int qla2x00_send_adisc_iocb(scsi_qla_host_t *, struct io_descriptor *, int);static int qla2x00_send_adisc_iocb_cb(scsi_qla_host_t *, struct io_descriptor *, struct mbx_entry *);static int qla2x00_send_logout_iocb(scsi_qla_host_t *, struct io_descriptor *, int);static int qla2x00_send_logout_iocb_cb(scsi_qla_host_t *, struct io_descriptor *, struct mbx_entry *);static int qla2x00_send_login_iocb(scsi_qla_host_t *, struct io_descriptor *, port_id_t *, int);static int qla2x00_send_login_iocb_cb(scsi_qla_host_t *, struct io_descriptor *, struct mbx_entry *);/** * Mailbox IOCB callback array. **/static int (*iocb_function_cb_list[LAST_IOCB_CB]) (scsi_qla_host_t *, struct io_descriptor *, struct mbx_entry *) = { qla2x00_send_abort_iocb_cb, qla2x00_send_adisc_iocb_cb, qla2x00_send_logout_iocb_cb, qla2x00_send_login_iocb_cb,};/** * Generic IO descriptor handle routines. **//** * qla2x00_to_handle() - Create a descriptor handle. * @type: descriptor type * @iter: descriptor rolling signature * @idx: index to the descriptor array * * Returns a composite handle based in the @type, @iter, and @idx. */static inline uint32_tqla2x00_to_handle(uint16_t type, uint16_t iter, uint16_t idx){ return ((uint32_t)(((uint32_t)type << HDL_TYPE_SHIFT) | ((uint32_t)iter << HDL_ITER_SHIFT) | ((uint32_t)idx << HDL_INDEX_SHIFT)));}/** * qla2x00_handle_to_idx() - Retrive the index for a given handle. * @handle: descriptor handle * * Returns the index specified by the @handle. */static inline uint16_tqla2x00_handle_to_idx(uint32_t handle){ return ((uint16_t)(((handle) >> HDL_INDEX_SHIFT) & HDL_INDEX_MASK));}/** * qla2x00_iodesc_to_handle() - Convert an IO descriptor to a unique handle. * @iodesc: io descriptor * * Returns a unique handle for @iodesc. */static inline uint32_tqla2x00_iodesc_to_handle(struct io_descriptor *iodesc){ uint32_t handle; handle = qla2x00_to_handle(HDL_TYPE_ASYNC_IOCB, ++iodesc->ha->iodesc_signature, iodesc->idx); iodesc->signature = handle; return (handle);}/** * qla2x00_handle_to_iodesc() - Retrieve an IO descriptor given a unique handle. * @ha: HA context * @handle: handle to io descriptor * * Returns a pointer to the io descriptor, or NULL, if the io descriptor does * not exist or the io descriptors signature does not @handle. */static inline struct io_descriptor *qla2x00_handle_to_iodesc(scsi_qla_host_t *ha, uint32_t handle){ uint16_t idx; struct io_descriptor *iodesc; idx = qla2x00_handle_to_idx(handle); iodesc = &ha->io_descriptors[idx]; if (iodesc) if (iodesc->signature != handle) iodesc = NULL; return (iodesc);}/** * IO descriptor allocation routines. **//** * qla2x00_alloc_iodesc() - Allocate an IO descriptor from the pool. * @ha: HA context * * Returns a pointer to the allocated io descriptor, or NULL, if none available. */static inline struct io_descriptor *qla2x00_alloc_iodesc(scsi_qla_host_t *ha){ uint16_t iter; struct io_descriptor *iodesc; iodesc = NULL; for (iter = 0; iter < MAX_IO_DESCRIPTORS; iter++) { if (ha->io_descriptors[iter].used) continue; iodesc = &ha->io_descriptors[iter]; iodesc->used = 1; iodesc->idx = iter; init_timer(&iodesc->timer); iodesc->ha = ha; iodesc->signature = qla2x00_iodesc_to_handle(iodesc); break; } return (iodesc);}/** * qla2x00_free_iodesc() - Free an IO descriptor. * @iodesc: io descriptor * * NOTE: The io descriptors timer *must* be stopped before it can be free'd. */static inline voidqla2x00_free_iodesc(struct io_descriptor *iodesc){ iodesc->used = 0; iodesc->signature = 0;}/** * qla2x00_remove_iodesc_timer() - Remove an active timer from an IO descriptor. * @iodesc: io descriptor */static inline voidqla2x00_remove_iodesc_timer(struct io_descriptor *iodesc){ if (iodesc->timer.function != NULL) { del_timer_sync(&iodesc->timer); iodesc->timer.data = (unsigned long) NULL; iodesc->timer.function = NULL; }}/** * qla2x00_init_io_descriptors() - Initialize the pool of IO descriptors. * @ha: HA context */static inline voidqla2x00_init_io_descriptors(scsi_qla_host_t *ha){ uint16_t iter; for (iter = 0; iter < MAX_IO_DESCRIPTORS; iter++) { if (!ha->io_descriptors[iter].used) continue; qla2x00_remove_iodesc_timer(&ha->io_descriptors[iter]); qla2x00_free_iodesc(&ha->io_descriptors[iter]); }}/** * IO descriptor timer routines. **//** * qla2x00_iodesc_timeout() - Timeout IO descriptor handler. * @data: io descriptor */static voidqla2x00_iodesc_timeout(unsigned long data){ struct io_descriptor *iodesc; iodesc = (struct io_descriptor *) data; DEBUG14(printk("scsi(%ld): IO descriptor timeout, index=%x " "signature=%08x, scheduling ISP abort.\n", iodesc->ha->host_no, iodesc->idx, iodesc->signature)); qla2x00_free_iodesc(iodesc); qla_printk(KERN_WARNING, iodesc->ha, "IO descriptor timeout. Scheduling ISP abort.\n"); set_bit(ISP_ABORT_NEEDED, &iodesc->ha->dpc_flags);}/** * qla2x00_add_iodesc_timer() - Add and start a timer for an IO descriptor. * @iodesc: io descriptor * * NOTE: * The firmware shall timeout an outstanding mailbox IOCB in 2 * R_A_TOV (in * tenths of a second) after it hits the wire. But, if there are any request * resource contraints (i.e. during heavy I/O), exchanges can be held off for * at most R_A_TOV. Therefore, the driver will wait 4 * R_A_TOV before * scheduling a recovery (big hammer). */static inline voidqla2x00_add_iodesc_timer(struct io_descriptor *iodesc){ unsigned long timeout; timeout = (iodesc->ha->r_a_tov * 4) / 10; init_timer(&iodesc->timer); iodesc->timer.data = (unsigned long) iodesc; iodesc->timer.expires = jiffies + (timeout * HZ); iodesc->timer.function = (void (*) (unsigned long)) qla2x00_iodesc_timeout; add_timer(&iodesc->timer);}/** * IO descriptor support routines. **//** * qla2x00_update_login_fcport() - Update fcport data after login processing. * @ha: HA context * @mbxstat: Mailbox command status IOCB * @fcport: port to update */static inline voidqla2x00_update_login_fcport(scsi_qla_host_t *ha, struct mbx_entry *mbxstat, fc_port_t *fcport){ if (le16_to_cpu(mbxstat->mb1) & BIT_0) { fcport->port_type = FCT_INITIATOR; } else { fcport->port_type = FCT_TARGET; if (le16_to_cpu(mbxstat->mb1) & BIT_1) { fcport->flags |= FCF_TAPE_PRESENT; } } fcport->login_retry = 0; fcport->port_login_retry_count = ha->port_down_retry_count * PORT_RETRY_TIME; atomic_set(&fcport->port_down_timer, ha->port_down_retry_count * PORT_RETRY_TIME); fcport->flags |= FCF_FABRIC_DEVICE; fcport->flags &= ~FCF_FAILOVER_NEEDED; fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; atomic_set(&fcport->state, FCS_ONLINE); schedule_work(&fcport->rport_add_work);}/** * Mailbox IOCB commands. **//** * qla2x00_get_mbx_iocb_entry() - Retrieve an IOCB from the request queue. * @ha: HA context * @handle: handle to io descriptor * * Returns a pointer to the reqest entry, or NULL, if none were available. */static inline struct mbx_entry *qla2x00_get_mbx_iocb_entry(scsi_qla_host_t *ha, uint32_t handle){ uint16_t cnt; struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; struct mbx_entry *mbxentry; mbxentry = NULL; if (ha->req_q_cnt < 3) { cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg)); if (ha->req_ring_index < cnt) ha->req_q_cnt = cnt - ha->req_ring_index; else ha->req_q_cnt = ha->request_q_length - (ha->req_ring_index - cnt); } if (ha->req_q_cnt >= 3) { mbxentry = (struct mbx_entry *)ha->request_ring_ptr; memset(mbxentry, 0, sizeof(struct mbx_entry)); mbxentry->entry_type = MBX_IOCB_TYPE; mbxentry->entry_count = 1; mbxentry->sys_define1 = SOURCE_ASYNC_IOCB; mbxentry->handle = handle; } return (mbxentry);}/** * qla2x00_send_abort_iocb() - Issue an abort IOCB to the firmware. * @ha: HA context * @iodesc: io descriptor * @handle_to_abort: firmware handle to abort * @ha_locked: is function called with the hardware lock * * Returns QLA_SUCCESS if the IOCB was issued. */static intqla2x00_send_abort_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, uint32_t handle_to_abort, int ha_locked){ unsigned long flags = 0; struct mbx_entry *mbxentry; /* Send marker if required. */ if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS) return (QLA_FUNCTION_FAILED); if (!ha_locked) spin_lock_irqsave(&ha->hardware_lock, flags); /* Build abort mailbox IOCB. */ mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature); if (mbxentry == NULL) { if (!ha_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); return (QLA_FUNCTION_FAILED); } mbxentry->mb0 = __constant_cpu_to_le16(MBC_ABORT_COMMAND); mbxentry->mb1 = mbxentry->loop_id.extended = cpu_to_le16(iodesc->remote_fcport->loop_id); mbxentry->mb2 = LSW(handle_to_abort); mbxentry->mb3 = MSW(handle_to_abort); wmb(); qla2x00_add_iodesc_timer(iodesc); /* Issue command to ISP. */ qla2x00_isp_cmd(ha); if (!ha_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); DEBUG14(printk("scsi(%ld): Sending Abort IOCB (%08x) to [%x], aborting " "%08x.\n", ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id, handle_to_abort)); return (QLA_SUCCESS);}/** * qla2x00_send_abort_iocb_cb() - Abort IOCB callback. * @ha: HA context * @iodesc: io descriptor * @mbxstat: mailbox status IOCB * * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc * will be used for a retry. */static intqla2x00_send_abort_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, struct mbx_entry *mbxstat){ DEBUG14(printk("scsi(%ld): Abort IOCB -- sent to [%x/%02x%02x%02x], " "status=%x mb0=%x.\n", ha->host_no, iodesc->remote_fcport->loop_id, iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa, le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0))); return (QLA_SUCCESS);}/** * qla2x00_send_adisc_iocb() - Issue a Get Port Database IOCB to the firmware. * @ha: HA context * @iodesc: io descriptor * @ha_locked: is function called with the hardware lock * * Returns QLA_SUCCESS if the IOCB was issued. */static intqla2x00_send_adisc_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, int ha_locked){ unsigned long flags = 0; struct mbx_entry *mbxentry; /* Send marker if required. */ if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS) return (QLA_FUNCTION_FAILED); if (!ha_locked) spin_lock_irqsave(&ha->hardware_lock, flags); /* Build Get Port Database IOCB. */ mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature); if (mbxentry == NULL) { if (!ha_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); return (QLA_FUNCTION_FAILED); } mbxentry->mb0 = __constant_cpu_to_le16(MBC_GET_PORT_DATABASE); mbxentry->mb1 = mbxentry->loop_id.extended = cpu_to_le16(iodesc->remote_fcport->loop_id); mbxentry->mb2 = cpu_to_le16(MSW(LSD(ha->iodesc_pd_dma))); mbxentry->mb3 = cpu_to_le16(LSW(LSD(ha->iodesc_pd_dma))); mbxentry->mb6 = cpu_to_le16(MSW(MSD(ha->iodesc_pd_dma)));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -