iph5526.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:148k
- /**********************************************************************
- * iph5526.c: IP/SCSI driver for the Interphase 5526 PCI Fibre Channel
- * Card.
- * Copyright (C) 1999 Vineet M Abraham <vmabraham@hotmail.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.
- *********************************************************************/
- /**********************************************************************
- Log:
- Vineet M Abraham
- 02.12.99 Support multiple cards.
- 03.15.99 Added Fabric support.
- 04.04.99 Added N_Port support.
- 04.15.99 Added SCSI support.
- 06.18.99 Added ABTS Protocol.
- 06.24.99 Fixed data corruption when multiple XFER_RDYs are received.
- 07.07.99 Can be loaded as part of the Kernel. Changed semaphores. Added
- more checks before invalidating SEST entries.
- 07.08.99 Added Broadcast IP stuff and fixed an unicast timeout bug.
- ***********************************************************************/
- /* TODO:
- R_T_TOV set to 15msec in Loop topology. Need to be 100 msec.
- SMP testing.
- Fix ADISC Tx before completing FLOGI.
- */
- static const char *version =
- "iph5526.c:v1.0 07.08.99 Vineet Abraham (vmabraham@hotmail.com)n";
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/errno.h>
- #include <linux/pci.h>
- #include <linux/init.h>
- #include <linux/mm.h>
- #include <linux/delay.h>
- #include <linux/skbuff.h>
- #include <linux/if_arp.h>
- #include <linux/timer.h>
- #include <linux/spinlock.h>
- #include <asm/system.h>
- #include <asm/io.h>
- #include <linux/netdevice.h>
- #include <linux/fcdevice.h> /* had the declarations for init_fcdev among others + includes if_fcdevice.h */
- #include <linux/blk.h>
- #include "../../scsi/sd.h"
- #include "../../scsi/scsi.h"
- #include "../../scsi/hosts.h"
- #include "../../fc4/fcp.h"
- /* driver specific header files */
- #include "tach.h"
- #include "tach_structs.h"
- #include "iph5526_ip.h"
- #include "iph5526_scsi.h"
- #include "iph5526_novram.c"
- #define RUN_AT(x) (jiffies + (x))
- #define DEBUG_5526_0 0
- #define DEBUG_5526_1 0
- #define DEBUG_5526_2 0
- #if DEBUG_5526_0
- #define DPRINTK(format, a...) {printk("%s: ", fi->name);
- printk(format, ##a);
- printk("n");}
- #define ENTER(x) {printk("%s: ", fi->name);
- printk("iph5526.c : entering %s()n", x);}
- #define LEAVE(x) {printk("%s: ", fi->name);
- printk("iph5526.c : leaving %s()n",x);}
- #else
- #define DPRINTK(format, a...) {}
- #define ENTER(x) {}
- #define LEAVE(x) {}
- #endif
- #if DEBUG_5526_1
- #define DPRINTK1(format, a...) {printk("%s: ", fi->name);
- printk(format, ##a);
- printk("n");}
- #else
- #define DPRINTK1(format, a...) {}
- #endif
- #if DEBUG_5526_2
- #define DPRINTK2(format, a...) {printk("%s: ", fi->name);
- printk(format, ##a);
- printk("n");}
- #else
- #define DPRINTK2(format, a...) {}
- #endif
- #define T_MSG(format, a...) {printk("%s: ", fi->name);
- printk(format, ##a);
- printk("n");}
- #define ALIGNED_SFS_ADDR(addr) ((((unsigned long)(addr) + (SFS_BUFFER_SIZE - 1)) & ~(SFS_BUFFER_SIZE - 1)) - (unsigned long)(addr))
- #define ALIGNED_ADDR(addr, len) ((((unsigned long)(addr) + (len - 1)) & ~(len - 1)) - (unsigned long)(addr))
- static struct pci_device_id iph5526_pci_tbl[] __initdata = {
- { PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_5526, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_55x6, PCI_ANY_ID, PCI_ANY_ID, },
- { } /* Terminating entry */
- };
- MODULE_DEVICE_TABLE(pci, iph5526_pci_tbl);
- MODULE_LICENSE("GPL");
- #define MAX_FC_CARDS 2
- static struct fc_info *fc[MAX_FC_CARDS+1];
- static unsigned int pci_irq_line;
- static struct {
- unsigned short vendor_id;
- unsigned short device_id;
- char *name;
- }
- clone_list[] __initdata = {
- {PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_5526, "Interphase Fibre Channel HBA"},
- {PCI_VENDOR_ID_INTERPHASE, PCI_DEVICE_ID_INTERPHASE_55x6, "Interphase Fibre Channel HBA"},
- {0,}
- };
- static void tachyon_interrupt(int irq, void *dev_id, struct pt_regs *regs);
- static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs);
- static int initialize_register_pointers(struct fc_info *fi);
- void clean_up_memory(struct fc_info *fi);
- static int tachyon_init(struct fc_info *fi);
- static int build_queues(struct fc_info *fi);
- static void build_tachyon_header(struct fc_info *fi, u_int my_id, u_int r_ctl, u_int d_id, u_int type, u_char seq_id, u_char df_ctl, u_short ox_id, u_short rx_id, char *data);
- static int get_free_header(struct fc_info *fi);
- static void build_EDB(struct fc_info *fi, char *data, u_short flags, u_short len);
- static int get_free_EDB(struct fc_info *fi);
- static void build_ODB(struct fc_info *fi, u_char seq_id, u_int d_id, u_int len, u_int cntl, u_short mtu, u_short ox_id, u_short rx_id, int NW_header, int int_required, u_int frame_class);
- static void write_to_tachyon_registers(struct fc_info *fi);
- static void reset_latch(struct fc_info *fi);
- static void reset_tachyon(struct fc_info *fi, u_int value);
- static void take_tachyon_offline(struct fc_info *fi);
- static void read_novram(struct fc_info *fi);
- static void reset_ichip(struct fc_info *fi);
- static void update_OCQ_indx(struct fc_info *fi);
- static void update_IMQ_indx(struct fc_info *fi, int count);
- static void update_SFSBQ_indx(struct fc_info *fi);
- static void update_MFSBQ_indx(struct fc_info *fi, int count);
- static void update_tachyon_header_indx(struct fc_info *fi);
- static void update_EDB_indx(struct fc_info *fi);
- static void handle_FM_interrupt(struct fc_info *fi);
- static void handle_MFS_interrupt(struct fc_info *fi);
- static void handle_OOO_interrupt(struct fc_info *fi);
- static void handle_SFS_interrupt(struct fc_info *fi);
- static void handle_OCI_interrupt(struct fc_info *fi);
- static void handle_SFS_BUF_WARN_interrupt(struct fc_info *fi);
- static void handle_MFS_BUF_WARN_interrupt(struct fc_info *fi);
- static void handle_IMQ_BUF_WARN_interrupt(struct fc_info *fi);
- static void handle_Unknown_Frame_interrupt(struct fc_info *fi);
- static void handle_Busied_Frame_interrupt(struct fc_info *fi);
- static void handle_Bad_SCSI_Frame_interrupt(struct fc_info *fi);
- static void handle_Inbound_SCSI_Status_interrupt(struct fc_info *fi);
- static void handle_Inbound_SCSI_Command_interrupt(struct fc_info *fi);
- static void completion_message_handler(struct fc_info *fi, u_int imq_int_type);
- static void fill_login_frame(struct fc_info *fi, u_int logi);
- static int tx_exchange(struct fc_info *fi, char *data, u_int len, u_int r_ctl, u_int type, u_int d_id, u_int mtu, int int_required, u_short ox_id, u_int frame_class);
- static int tx_sequence(struct fc_info *fi, char *data, u_int len, u_int mtu, u_int d_id, u_short ox_id, u_short rx_id, u_char seq_id, int NW_flag, int int_required, u_int frame_class);
- static int validate_login(struct fc_info *fi, u_int *base_ptr);
- static void add_to_address_cache(struct fc_info *fi, u_int *base_ptr);
- static void remove_from_address_cache(struct fc_info *fi, u_int *data, u_int cmnd_code);
- static int node_logged_in_prev(struct fc_info *fi, u_int *buff_addr);
- static int sid_logged_in(struct fc_info *fi, u_int s_id);
- static struct fc_node_info *look_up_cache(struct fc_info *fi, char *data);
- static int display_cache(struct fc_info *fi);
- static void tx_logi(struct fc_info *fi, u_int logi, u_int d_id);
- static void tx_logi_acc(struct fc_info *fi, u_int logi, u_int d_id, u_short received_ox_id);
- static void tx_prli(struct fc_info *fi, u_int command_code, u_int d_id, u_short received_ox_id);
- static void tx_logo(struct fc_info *fi, u_int d_id, u_short received_ox_id);
- static void tx_adisc(struct fc_info *fi, u_int cmnd_code, u_int d_id, u_short received_ox_id);
- static void tx_ls_rjt(struct fc_info *fi, u_int d_id, u_short received_ox_id, u_short reason_code, u_short expln_code);
- static u_int plogi_ok(struct fc_info *fi, u_int *buff_addr, int size);
- static void tx_acc(struct fc_info *fi, u_int d_id, u_short received_ox_id);
- static void tx_name_server_req(struct fc_info *fi, u_int req);
- static void rscn_handler(struct fc_info *fi, u_int node_id);
- static void tx_scr(struct fc_info *fi);
- static void scr_timer(unsigned long data);
- static void explore_fabric(struct fc_info *fi, u_int *buff_addr);
- static void perform_adisc(struct fc_info *fi);
- static void local_port_discovery(struct fc_info *fi);
- static void add_to_ox_id_list(struct fc_info *fi, u_int transaction_id, u_int cmnd_code);
- static u_int remove_from_ox_id_list(struct fc_info *fi, u_short received_ox_id);
- static void add_display_cache_timer(struct fc_info *fi);
- /* Timers... */
- static void nos_ols_timer(unsigned long data);
- static void loop_timer(unsigned long data);
- static void fabric_explore_timer(unsigned long data);
- static void port_discovery_timer(unsigned long data);
- static void display_cache_timer(unsigned long data);
- /* SCSI Stuff */
- static int add_to_sest(struct fc_info *fi, Scsi_Cmnd *Cmnd, struct fc_node_info *ni);
- static struct fc_node_info *resolve_target(struct fc_info *fi, u_char target);
- static void update_FCP_CMND_indx(struct fc_info *fi);
- static int get_free_SDB(struct fc_info *fi);
- static void update_SDB_indx(struct fc_info *fi);
- static void mark_scsi_sid(struct fc_info *fi, u_int *buff_addr, u_char action);
- static void invalidate_SEST_entry(struct fc_info *fi, u_short received_ox_id);
- static int abort_exchange(struct fc_info *fi, u_short ox_id);
- static void flush_tachyon_cache(struct fc_info *fi, u_short ox_id);
- static int get_scsi_oxid(struct fc_info *fi);
- static void update_scsi_oxid(struct fc_info *fi);
- static Scsi_Host_Template driver_template = IPH5526_SCSI_FC;
- static void iph5526_timeout(struct net_device *dev);
- static int iph5526_probe_pci(struct net_device *dev);
- int __init iph5526_probe(struct net_device *dev)
- {
- if (pci_present() && (iph5526_probe_pci(dev) == 0))
- return 0;
- return -ENODEV;
- }
- static int __init iph5526_probe_pci(struct net_device *dev)
- {
- #ifdef MODULE
- struct fc_info *fi = (struct fc_info *)dev->priv;
- #else
- struct fc_info *fi;
- static int count;
-
- if(fc[count] != NULL) {
- if (dev == NULL) {
- dev = init_fcdev(NULL, 0);
- if (dev == NULL)
- return -ENOMEM;
- }
- fi = fc[count];
- #endif
- fi->dev = dev;
- dev->base_addr = fi->base_addr;
- dev->irq = fi->irq;
- if (dev->priv == NULL)
- dev->priv = fi;
- fcdev_init(dev);
- /* Assign ur MAC address.
- */
- dev->dev_addr[0] = (fi->g.my_port_name_high & 0x0000FF00) >> 8;
- dev->dev_addr[1] = fi->g.my_port_name_high;
- dev->dev_addr[2] = (fi->g.my_port_name_low & 0xFF000000) >> 24;
- dev->dev_addr[3] = (fi->g.my_port_name_low & 0x00FF0000) >> 16;
- dev->dev_addr[4] = (fi->g.my_port_name_low & 0x0000FF00) >> 8;
- dev->dev_addr[5] = fi->g.my_port_name_low;
- #ifndef MODULE
- count++;
- }
- else
- return -ENODEV;
- #endif
- display_cache(fi);
- return 0;
- }
- static int __init fcdev_init(struct net_device *dev)
- {
- dev->open = iph5526_open;
- dev->stop = iph5526_close;
- dev->hard_start_xmit = iph5526_send_packet;
- dev->get_stats = iph5526_get_stats;
- dev->set_multicast_list = NULL;
- dev->change_mtu = iph5526_change_mtu;
- dev->tx_timeout = iph5526_timeout;
- dev->watchdog_timeo = 5*HZ;
- #ifndef MODULE
- fc_setup(dev);
- #endif
- return 0;
- }
- /* initialize tachyon and take it OnLine */
- static int tachyon_init(struct fc_info *fi)
- {
- ENTER("tachyon_init");
- if (build_queues(fi) == 0) {
- T_MSG("build_queues() failed");
- return 0;
- }
- /* Retrieve your port/node name.
- */
- read_novram(fi);
- reset_ichip(fi);
- reset_tachyon(fi, SOFTWARE_RESET);
- LEAVE("tachyon_init");
- return 1;
- }
- /* Build the 4 Qs - IMQ, OCQ, MFSBQ, SFSBQ */
- /* Lots of dma_pages needed as Tachyon DMAs almost everything into
- * host memory.
- */
- static int build_queues(struct fc_info *fi)
- {
- int i,j;
- u_char *addr;
- ENTER("build_queues");
- /* Initializing Queue Variables.
- */
- fi->q.ptr_host_ocq_cons_indx = NULL;
- fi->q.ptr_host_hpcq_cons_indx = NULL;
- fi->q.ptr_host_imq_prod_indx = NULL;
- fi->q.ptr_ocq_base = NULL;
- fi->q.ocq_len = 0;
- fi->q.ocq_end = 0;
- fi->q.ocq_prod_indx = 0;
- fi->q.ptr_imq_base = NULL;
- fi->q.imq_len = 0;
- fi->q.imq_end = 0;
- fi->q.imq_cons_indx = 0;
- fi->q.imq_prod_indx = 0;
- fi->q.ptr_mfsbq_base = NULL;
- fi->q.mfsbq_len = 0;
- fi->q.mfsbq_end = 0;
- fi->q.mfsbq_prod_indx = 0;
- fi->q.mfsbq_cons_indx = 0;
- fi->q.mfsbuff_len = 0;
- fi->q.mfsbuff_end = 0;
- fi->g.mfs_buffer_count = 0;
- fi->q.ptr_sfsbq_base = NULL;
- fi->q.sfsbq_len = 0;
- fi->q.sfsbq_end = 0;
- fi->q.sfsbq_prod_indx = 0;
- fi->q.sfsbq_cons_indx = 0;
- fi->q.sfsbuff_len = 0;
- fi->q.sfsbuff_end = 0;
- fi->q.sdb_indx = 0;
- fi->q.fcp_cmnd_indx = 0;
- fi->q.ptr_edb_base = NULL;
- fi->q.edb_buffer_indx = 0;
- fi->q.ptr_tachyon_header_base = NULL;
- fi->q.tachyon_header_indx = 0;
- fi->node_info_list = NULL;
- fi->ox_id_list = NULL;
- fi->g.loop_up = FALSE;
- fi->g.ptp_up = FALSE;
- fi->g.link_up = FALSE;
- fi->g.fabric_present = FALSE;
- fi->g.n_port_try = FALSE;
- fi->g.dont_init = FALSE;
- fi->g.nport_timer_set = FALSE;
- fi->g.lport_timer_set = FALSE;
- fi->g.no_of_targets = 0;
- fi->g.sem = 0;
- fi->g.perform_adisc = FALSE;
- fi->g.e_i = 0;
- /* build OCQ */
- if ( (fi->q.ptr_ocq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
- T_MSG("failed to get OCQ page");
- return 0;
- }
- /* set up the OCQ structures */
- for (i = 0; i < OCQ_LENGTH; i++)
- fi->q.ptr_odb[i] = fi->q.ptr_ocq_base + NO_OF_ENTRIES*i;
- /* build IMQ */
- if ( (fi->q.ptr_imq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
- T_MSG("failed to get IMQ page");
- return 0;
- }
- for (i = 0; i < IMQ_LENGTH; i++)
- fi->q.ptr_imqe[i] = fi->q.ptr_imq_base + NO_OF_ENTRIES*i;
- /* build MFSBQ */
- if ( (fi->q.ptr_mfsbq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
- T_MSG("failed to get MFSBQ page");
- return 0;
- }
- memset((char *)fi->q.ptr_mfsbq_base, 0, MFSBQ_LENGTH * 32);
- /* Allocate one huge chunk of memory... helps while reassembling
- * frames.
- */
- if ( (addr = (u_char *)__get_free_pages(GFP_KERNEL, 5) ) == 0) {
- T_MSG("failed to get MFSBQ page");
- return 0;
- }
- /* fill in addresses of empty buffers */
- for (i = 0; i < MFSBQ_LENGTH; i++) {
- for (j = 0; j < NO_OF_ENTRIES; j++) {
- *(fi->q.ptr_mfsbq_base + i*NO_OF_ENTRIES + j) = htonl(virt_to_bus(addr));
- addr += MFS_BUFFER_SIZE;
- }
- }
- /* The number of entries in each MFS buffer is 8. There are 8
- * MFS buffers. That leaves us with 4096-256 bytes. We use them
- * as temporary space for ELS frames. This is done to make sure that
- * the addresses are aligned.
- */
- fi->g.els_buffer[0] = fi->q.ptr_mfsbq_base + MFSBQ_LENGTH*NO_OF_ENTRIES;
- for (i = 1; i < MAX_PENDING_FRAMES; i++)
- fi->g.els_buffer[i] = fi->g.els_buffer[i-1] + 64;
-
- /* build SFSBQ */
- if ( (fi->q.ptr_sfsbq_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
- T_MSG("failed to get SFSBQ page");
- return 0;
- }
- memset((char *)fi->q.ptr_sfsbq_base, 0, SFSBQ_LENGTH * 32);
- /* fill in addresses of empty buffers */
- for (i = 0; i < SFSBQ_LENGTH; i++)
- for (j = 0; j < NO_OF_ENTRIES; j++){
- addr = kmalloc(SFS_BUFFER_SIZE*2, GFP_KERNEL);
- if (addr == NULL){
- T_MSG("ptr_sfs_buffer : memory not allocated");
- return 0;
- }
- else {
- int offset = ALIGNED_SFS_ADDR(addr);
- memset((char *)addr, 0, SFS_BUFFER_SIZE);
- fi->q.ptr_sfs_buffers[i*NO_OF_ENTRIES +j] = (u_int *)addr;
- addr += offset;
- *(fi->q.ptr_sfsbq_base + i*NO_OF_ENTRIES + j) = htonl(virt_to_bus(addr));
- }
- }
- /* The number of entries in each SFS buffer is 8. There are 8
- * MFS buffers. That leaves us with 4096-256 bytes. We use them
- * as temporary space for ARP frames. This is done inorder to
- * support HW_Types of 0x1 and 0x6.
- */
- fi->g.arp_buffer = (char *)fi->q.ptr_sfsbq_base + SFSBQ_LENGTH*NO_OF_ENTRIES*4;
-
- /* build EDB */
- if ((fi->q.ptr_edb_base = (u_int *)__get_free_pages(GFP_KERNEL, 5) ) == 0) {
- T_MSG("failed to get EDB page");
- return 0;
- }
- for (i = 0; i < EDB_LEN; i++)
- fi->q.ptr_edb[i] = fi->q.ptr_edb_base + 2*i;
- /* build SEST */
- /* OX_IDs range from 0x0 - 0x4FFF.
- */
- if ((fi->q.ptr_sest_base = (u_int *)__get_free_pages(GFP_KERNEL, 5)) == 0) {
- T_MSG("failed to get SEST page");
- return 0;
- }
- for (i = 0; i < SEST_LENGTH; i++)
- fi->q.ptr_sest[i] = fi->q.ptr_sest_base + NO_OF_ENTRIES*i;
-
- if ((fi->q.ptr_sdb_base = (u_int *)__get_free_pages(GFP_KERNEL, 5)) == 0) {
- T_MSG("failed to get SDB page");
- return 0;
- }
- for (i = 0 ; i < NO_OF_SDB_ENTRIES; i++)
- fi->q.ptr_sdb_slot[i] = fi->q.ptr_sdb_base + (SDB_SIZE/4)*i;
- if ((fi->q.ptr_fcp_cmnd_base = (u_int *)__get_free_pages(GFP_KERNEL, 0)) == 0) {
- T_MSG("failed to get FCP_CMND page");
- return 0;
- }
- for (i = 0; i < NO_OF_FCP_CMNDS; i++)
- fi->q.ptr_fcp_cmnd[i] = fi->q.ptr_fcp_cmnd_base + NO_OF_ENTRIES*i;
- /* Allocate space for Tachyon Header as well...
- */
- if ((fi->q.ptr_tachyon_header_base = (u_int *)__get_free_pages(GFP_KERNEL, 0) ) == 0) {
- T_MSG("failed to get tachyon_header page");
- return 0;
- }
- for (i = 0; i < NO_OF_TACH_HEADERS; i++)
- fi->q.ptr_tachyon_header[i] = fi->q.ptr_tachyon_header_base + 16*i;
-
- /* Allocate memory for indices.
- * Indices should be aligned on 32 byte boundries.
- */
- fi->q.host_ocq_cons_indx = kmalloc(2*32, GFP_KERNEL);
- if (fi->q.host_ocq_cons_indx == NULL){
- T_MSG("fi->q.host_ocq_cons_indx : memory not allocated");
- return 0;
- }
- fi->q.ptr_host_ocq_cons_indx = fi->q.host_ocq_cons_indx;
- if ((u_long)(fi->q.host_ocq_cons_indx) % 32)
- fi->q.host_ocq_cons_indx++;
-
- fi->q.host_hpcq_cons_indx = kmalloc(2*32, GFP_KERNEL);
- if (fi->q.host_hpcq_cons_indx == NULL){
- T_MSG("fi->q.host_hpcq_cons_indx : memory not allocated");
- return 0;
- }
- fi->q.ptr_host_hpcq_cons_indx= fi->q.host_hpcq_cons_indx;
- if ((u_long)(fi->q.host_hpcq_cons_indx) % 32)
- fi->q.host_hpcq_cons_indx++;
- fi->q.host_imq_prod_indx = kmalloc(2*32, GFP_KERNEL);
- if (fi->q.host_imq_prod_indx == NULL){
- T_MSG("fi->q.host_imq_prod_indx : memory not allocated");
- return 0;
- }
- fi->q.ptr_host_imq_prod_indx = fi->q.host_imq_prod_indx;
- if ((u_long)(fi->q.host_imq_prod_indx) % 32)
- fi->q.host_imq_prod_indx++;
- LEAVE("build_queues");
- return 1;
- }
- static void write_to_tachyon_registers(struct fc_info *fi)
- {
- u_int bus_addr, bus_indx_addr, i;
- ENTER("write_to_tachyon_registers");
- /* Clear Queues each time Tachyon is reset */
- memset((char *)fi->q.ptr_ocq_base, 0, OCQ_LENGTH * 32);
- memset((char *)fi->q.ptr_imq_base, 0, IMQ_LENGTH * 32);
- memset((char *)fi->q.ptr_edb_base, 0, EDB_LEN * 8);
- memset((char *)fi->q.ptr_sest_base, 0, SEST_LENGTH * 32);
- memset((char *)fi->q.ptr_sdb_base, 0, NO_OF_SDB_ENTRIES * SDB_SIZE);
- memset((char *)fi->q.ptr_tachyon_header_base, 0xFF, NO_OF_TACH_HEADERS * TACH_HEADER_SIZE);
- for (i = 0; i < SEST_LENGTH; i++)
- fi->q.free_scsi_oxid[i] = OXID_AVAILABLE;
- for (i = 0; i < NO_OF_SDB_ENTRIES; i++)
- fi->q.sdb_slot_status[i] = SDB_FREE;
- take_tachyon_offline(fi);
- writel(readl(fi->t_r.ptr_tach_config_reg) | SCSI_ENABLE | WRITE_STREAM_SIZE | READ_STREAM_SIZE | PARITY_EVEN | OOO_REASSEMBLY_DISABLE, fi->t_r.ptr_tach_config_reg);
- /* Write OCQ registers */
- fi->q.ocq_prod_indx = 0;
- *(fi->q.host_ocq_cons_indx) = 0;
-
- /* The Tachyon needs to be passed the "real" address */
- bus_addr = virt_to_bus(fi->q.ptr_ocq_base);
- writel(bus_addr, fi->t_r.ptr_ocq_base_reg);
- writel(OCQ_LENGTH - 1, fi->t_r. ptr_ocq_len_reg);
- bus_indx_addr = virt_to_bus(fi->q.host_ocq_cons_indx);
- writel(bus_indx_addr, fi->t_r.ptr_ocq_cons_indx_reg);
- /* Write IMQ registers */
- fi->q.imq_cons_indx = 0;
- *(fi->q.host_imq_prod_indx) = 0;
- bus_addr = virt_to_bus(fi->q.ptr_imq_base);
- writel(bus_addr, fi->t_r.ptr_imq_base_reg);
- writel(IMQ_LENGTH - 1, fi->t_r.ptr_imq_len_reg);
- bus_indx_addr = virt_to_bus(fi->q.host_imq_prod_indx);
- writel(bus_indx_addr, fi->t_r.ptr_imq_prod_indx_reg);
-
- /* Write MFSBQ registers */
- fi->q.mfsbq_prod_indx = MFSBQ_LENGTH - 1;
- fi->q.mfsbuff_end = MFS_BUFFER_SIZE - 1;
- fi->q.mfsbq_cons_indx = 0;
- bus_addr = virt_to_bus(fi->q.ptr_mfsbq_base);
- writel(bus_addr, fi->t_r.ptr_mfsbq_base_reg);
- writel(MFSBQ_LENGTH - 1, fi->t_r.ptr_mfsbq_len_reg);
- writel(fi->q.mfsbuff_end, fi->t_r.ptr_mfsbuff_len_reg);
- /* Do this last as tachyon will prefetch the
- * first entry as soon as we write to it.
- */
- writel(fi->q.mfsbq_prod_indx, fi->t_r.ptr_mfsbq_prod_reg);
- /* Write SFSBQ registers */
- fi->q.sfsbq_prod_indx = SFSBQ_LENGTH - 1;
- fi->q.sfsbuff_end = SFS_BUFFER_SIZE - 1;
- fi->q.sfsbq_cons_indx = 0;
- bus_addr = virt_to_bus(fi->q.ptr_sfsbq_base);
- writel(bus_addr, fi->t_r.ptr_sfsbq_base_reg);
- writel(SFSBQ_LENGTH - 1, fi->t_r.ptr_sfsbq_len_reg);
- writel(fi->q.sfsbuff_end, fi->t_r.ptr_sfsbuff_len_reg);
- /* Do this last as tachyon will prefetch the first
- * entry as soon as we write to it.
- */
- writel(fi->q.sfsbq_prod_indx, fi->t_r.ptr_sfsbq_prod_reg);
- /* Write SEST registers */
- bus_addr = virt_to_bus(fi->q.ptr_sest_base);
- writel(bus_addr, fi->t_r.ptr_sest_base_reg);
- writel(SEST_LENGTH - 1, fi->t_r.ptr_sest_len_reg);
- /* the last 2 bits _should_ be 1 */
- writel(SEST_BUFFER_SIZE - 1, fi->t_r.ptr_scsibuff_len_reg);
- /* write AL_TIME & E_D_TOV into the registers */
- writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
- /* Tell Tachyon to pick a Soft Assigned AL_PA */
- writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg);
- /* Read the WWN from EEPROM . But, for now we assign it here. */
- writel(WORLD_WIDE_NAME_LOW, fi->t_r.ptr_fm_wwn_low_reg);
- writel(WORLD_WIDE_NAME_HIGH, fi->t_r.ptr_fm_wwn_hi_reg);
- DPRINTK1("TACHYON initializing as L_Port...n");
- writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
-
- LEAVE("write_to_tachyon_registers");
- }
- static void tachyon_interrupt(int irq, void* dev_id, struct pt_regs* regs)
- {
- struct Scsi_Host *host = dev_id;
- struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
- struct fc_info *fi = hostdata->fi;
- u_long flags;
- spin_lock_irqsave(&fi->fc_lock, flags);
- tachyon_interrupt_handler(irq, dev_id, regs);
- spin_unlock_irqrestore(&fi->fc_lock, flags);
- }
- static void tachyon_interrupt_handler(int irq, void* dev_id, struct pt_regs* regs)
- {
- struct Scsi_Host *host = dev_id;
- struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
- struct fc_info *fi = hostdata->fi;
- u_int *ptr_imq_entry;
- u_int imq_int_type, current_IMQ_index = 0, prev_IMQ_index;
- int index, no_of_entries = 0;
- DPRINTK("n");
- ENTER("tachyon_interrupt");
- if (fi->q.host_imq_prod_indx != NULL) {
- current_IMQ_index = ntohl(*(fi->q.host_imq_prod_indx));
- }
- else {
- /* _Should not_ happen */
- T_MSG("IMQ_indx NULL. DISABLING INTERRUPTS!!!n");
- writel(0x0, fi->i_r.ptr_ichip_hw_control_reg);
- }
- if (current_IMQ_index > fi->q.imq_cons_indx)
- no_of_entries = current_IMQ_index - fi->q.imq_cons_indx;
- else
- if (current_IMQ_index < fi->q.imq_cons_indx)
- no_of_entries = IMQ_LENGTH - (fi->q.imq_cons_indx - current_IMQ_index);
- if (no_of_entries == 0) {
- u_int ichip_status;
- ichip_status = readl(fi->i_r.ptr_ichip_hw_status_reg);
- if (ichip_status & 0x20) {
- /* Should _never_ happen. Might require a hard reset */
- T_MSG("Too bad... PCI Bus Error. Resetting (i)chip");
- reset_ichip(fi);
- T_MSG("DISABLING INTERRUPTS!!!n");
- writel(0x0, fi->i_r.ptr_ichip_hw_control_reg);
- }
- }
- prev_IMQ_index = current_IMQ_index;
- for (index = 0; index < no_of_entries; index++) {
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- imq_int_type = ntohl(*ptr_imq_entry);
- completion_message_handler(fi, imq_int_type);
- if ((fi->g.link_up == FALSE) && ((imq_int_type == MFS_BUF_WARN) || (imq_int_type == SFS_BUF_WARN) || (imq_int_type == IMQ_BUF_WARN)))
- break;
- update_IMQ_indx(fi, 1);
-
- /* Check for more entries */
- current_IMQ_index = ntohl(*(fi->q.host_imq_prod_indx));
- if (current_IMQ_index != prev_IMQ_index) {
- no_of_entries++;
- prev_IMQ_index = current_IMQ_index;
- }
- } /*end of for loop*/
- return;
- LEAVE("tachyon_interrupt");
- }
- static void handle_SFS_BUF_WARN_interrupt(struct fc_info *fi)
- {
- int i;
- ENTER("handle_SFS_BUF_WARN_interrupt");
- if (fi->g.link_up == FALSE) {
- reset_tachyon(fi, SOFTWARE_RESET);
- return;
- }
- /* Free up all but one entry in the Q.
- */
- for (i = 0; i < ((SFSBQ_LENGTH - 1) * NO_OF_ENTRIES); i++) {
- handle_SFS_interrupt(fi);
- update_IMQ_indx(fi, 1);
- }
- LEAVE("handle_SFS_BUF_WARN_interrupt");
- }
- /* Untested_Code_Begin */
- static void handle_MFS_BUF_WARN_interrupt(struct fc_info *fi)
- {
- int i;
- ENTER("handle_MFS_BUF_WARN_interrupt");
- if (fi->g.link_up == FALSE) {
- reset_tachyon(fi, SOFTWARE_RESET);
- return;
- }
- /* FIXME: freeing up 8 entries.
- */
- for (i = 0; i < NO_OF_ENTRIES; i++) {
- handle_MFS_interrupt(fi);
- update_IMQ_indx(fi, 1);
- }
- LEAVE("handle_MFS_BUF_WARN_interrupt");
- }
- /*Untested_Code_End */
- static void handle_IMQ_BUF_WARN_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry;
- u_int imq_int_type, current_IMQ_index = 0, temp_imq_cons_indx;
- int index, no_of_entries = 0;
- ENTER("handle_IMQ_BUF_WARN_interrupt");
- if (fi->g.link_up == FALSE) {
- reset_tachyon(fi, SOFTWARE_RESET);
- return;
- }
- current_IMQ_index = ntohl(*(fi->q.host_imq_prod_indx));
- if (current_IMQ_index > fi->q.imq_cons_indx)
- no_of_entries = current_IMQ_index - fi->q.imq_cons_indx;
- else
- if (current_IMQ_index < fi->q.imq_cons_indx)
- no_of_entries = IMQ_LENGTH - (fi->q.imq_cons_indx - current_IMQ_index);
- /* We dont want to look at the same IMQ entry again.
- */
- temp_imq_cons_indx = fi->q.imq_cons_indx + 1;
- if (no_of_entries != 0)
- no_of_entries -= 1;
- for (index = 0; index < no_of_entries; index++) {
- ptr_imq_entry = fi->q.ptr_imqe[temp_imq_cons_indx];
- imq_int_type = ntohl(*ptr_imq_entry);
- if (imq_int_type != IMQ_BUF_WARN)
- completion_message_handler(fi, imq_int_type);
- temp_imq_cons_indx++;
- if (temp_imq_cons_indx == IMQ_LENGTH)
- temp_imq_cons_indx = 0;
- } /*end of for loop*/
- if (no_of_entries != 0)
- update_IMQ_indx(fi, no_of_entries);
- LEAVE("handle_IMQ_BUF_WARN_interrupt");
- }
- static void completion_message_handler(struct fc_info *fi, u_int imq_int_type)
- {
- switch(imq_int_type) {
- case OUTBOUND_COMPLETION:
- DPRINTK("OUTBOUND_COMPLETION message received");
- break;
- case OUTBOUND_COMPLETION_I:
- DPRINTK("OUTBOUND_COMPLETION_I message received");
- handle_OCI_interrupt(fi);
- break;
- case OUT_HI_PRI_COMPLETION:
- DPRINTK("OUT_HI_PRI_COMPLETION message received");
- break;
- case OUT_HI_PRI_COMPLETION_I:
- DPRINTK("OUT_HI_PRI_COMPLETION_I message received");
- break;
- case INBOUND_MFS_COMPLETION:
- DPRINTK("INBOUND_MFS_COMPLETION message received");
- handle_MFS_interrupt(fi);
- break;
- case INBOUND_OOO_COMPLETION:
- DPRINTK("INBOUND_OOO_COMPLETION message received");
- handle_OOO_interrupt(fi);
- break;
- case INBOUND_SFS_COMPLETION:
- DPRINTK("INBOUND_SFS_COMPLETION message received");
- handle_SFS_interrupt(fi);
- break;
- case INBOUND_UNKNOWN_FRAME_I:
- DPRINTK("INBOUND_UNKNOWN_FRAME message received");
- handle_Unknown_Frame_interrupt(fi);
- break;
- case INBOUND_BUSIED_FRAME:
- DPRINTK("INBOUND_BUSIED_FRAME message received");
- handle_Busied_Frame_interrupt(fi);
- break;
- case FRAME_MGR_INTERRUPT:
- DPRINTK("FRAME_MGR_INTERRUPT message received");
- handle_FM_interrupt(fi);
- break;
- case READ_STATUS:
- DPRINTK("READ_STATUS message received");
- break;
- case SFS_BUF_WARN:
- DPRINTK("SFS_BUF_WARN message received");
- handle_SFS_BUF_WARN_interrupt(fi);
- break;
- case MFS_BUF_WARN:
- DPRINTK("MFS_BUF_WARN message received");
- handle_MFS_BUF_WARN_interrupt(fi);
- break;
- case IMQ_BUF_WARN:
- DPRINTK("IMQ_BUF_WARN message received");
- handle_IMQ_BUF_WARN_interrupt(fi);
- break;
- case INBOUND_C1_TIMEOUT:
- DPRINTK("INBOUND_C1_TIMEOUT message received");
- break;
- case BAD_SCSI_FRAME:
- DPRINTK("BAD_SCSI_FRAME message received");
- handle_Bad_SCSI_Frame_interrupt(fi);
- break;
- case INB_SCSI_STATUS_COMPLETION:
- DPRINTK("INB_SCSI_STATUS_COMPL message received");
- handle_Inbound_SCSI_Status_interrupt(fi);
- break;
- case INBOUND_SCSI_COMMAND:
- DPRINTK("INBOUND_SCSI_COMMAND message received");
- handle_Inbound_SCSI_Command_interrupt(fi);
- break;
- case INBOUND_SCSI_DATA_COMPLETION:
- DPRINTK("INBOUND_SCSI_DATA message received");
- /* Only for targets */
- break;
- default:
- T_MSG("DEFAULT message received, type = %x", imq_int_type);
- return;
- }
- reset_latch(fi);
- }
- static void handle_OCI_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry;
- u_long transaction_id = 0;
- unsigned short status, seq_count, transmitted_ox_id;
- struct Scsi_Host *host = fi->host;
- struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
- Scsi_Cmnd *Cmnd;
- u_int tag;
- ENTER("handle_OCI_interrupt");
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- transaction_id = ntohl(*(ptr_imq_entry + 1));
- status = ntohl(*(ptr_imq_entry + 2)) >> 16;
- seq_count = ntohl(*(ptr_imq_entry + 3));
- DPRINTK("transaction_id= %x", (u_int)transaction_id);
- tag = transaction_id & 0xFFFF0000;
- transmitted_ox_id = transaction_id;
- /* The INT could be either due to TIME_OUT | BAD_ALPA.
- * But we check only for TimeOuts. Bad AL_PA will
- * caught by FM_interrupt handler.
- */
- if ((status == OCM_TIMEOUT_OR_BAD_ALPA) && (!fi->g.port_discovery) && (!fi->g.perform_adisc)){
- DPRINTK("Frame TimeOut on OX_ID = %x", (u_int)transaction_id);
- /* Is it a SCSI frame that is timing out ? Not a very good check...
- */
- if ((transmitted_ox_id <= MAX_SCSI_OXID) && ((tag == FC_SCSI_BAD_TARGET) || (tag < 0x00FF0000))) {
- /* If it is a Bad AL_PA, we report it as BAD_TARGET.
- * Else, we allow the command to time-out. A Link
- * re-initialization could be taking place.
- */
- if (tag == FC_SCSI_BAD_TARGET) {
- Cmnd = hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID];
- hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID] = NULL;
- if (Cmnd != NULL) {
- Cmnd->result = DID_BAD_TARGET << 16;
- (*Cmnd->scsi_done) (Cmnd);
- }
- else
- T_MSG("NULL Command out of handler!");
- } /* if Bad Target */
- else {
- u_char missing_target = tag >> 16;
- struct fc_node_info *q = fi->node_info_list;
- /* A Node that we thought was logged in has gone
- * away. We are the optimistic kind and we keep
- * hoping that our dear little Target will come back
- * to us. For now we log him out.
- */
- DPRINTK2("Missing Target = %d", missing_target);
- while (q != NULL) {
- if (q->target_id == missing_target) {
- T_MSG("Target %d Logged out", q->target_id);
- q->login = LOGIN_ATTEMPTED;
- if (fi->num_nodes > 0)
- fi->num_nodes--;
- tx_logi(fi, ELS_PLOGI, q->d_id);
- break;
- }
- else
- q = q->next;
- }
- }
- } /* End of SCSI frame timing out. */
- else {
- if (seq_count > 1) {
- /* An IP frame was transmitted to a Bad AL_PA. Free up
- * the skb used.
- */
- dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
- netif_wake_queue(fi->dev);
- }
- } /* End of IP frame timing out. */
- } /* End of frame timing out. */
- else {
- /* Frame was transmitted successfully. Check if it was an ELS
- * frame or an IP frame or a Bad_Target_Notification frame (in
- * case of a ptp_link). Ugly!
- */
- if ((status == 0) && (seq_count == 0)) {
- u_int tag = transaction_id & 0xFFFF0000;
- /* Continue with port discovery after an ELS is successfully
- * transmitted. (status == 0).
- */
- DPRINTK("tag = %x", tag);
- switch(tag) {
- case ELS_FLOGI:
- /* Letz use the Name Server instead */
- fi->g.explore_fabric = TRUE;
- fi->g.port_discovery = FALSE;
- fi->g.alpa_list_index = MAX_NODES;
- add_to_ox_id_list(fi, transaction_id, tag);
- break;
- case ELS_PLOGI:
- if (fi->g.fabric_present && (fi->g.name_server == FALSE))
- add_to_ox_id_list(fi,transaction_id,ELS_NS_PLOGI);
- else
- add_to_ox_id_list(fi, transaction_id, tag);
- break;
- case FC_SCSI_BAD_TARGET:
- Cmnd = hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID];
- hostdata->cmnd_handler[transmitted_ox_id & MAX_SCSI_XID] = NULL;
- if (Cmnd != NULL) {
- Cmnd->result = DID_BAD_TARGET << 16;
- (*Cmnd->scsi_done) (Cmnd);
- }
- else
- T_MSG("NULL Command out of handler!");
- break;
- default:
- add_to_ox_id_list(fi, transaction_id, tag);
- }
-
- if (fi->g.alpa_list_index >= MAX_NODES) {
- if (fi->g.port_discovery == TRUE) {
- fi->g.port_discovery = FALSE;
- add_display_cache_timer(fi);
- }
- fi->g.alpa_list_index = MAX_NODES;
- }
- if (fi->g.port_discovery == TRUE)
- local_port_discovery(fi);
- }
- else {
- /* An IP frame has been successfully transmitted.
- * Free the skb that was used for this IP frame.
- */
- if ((status == 0) && (seq_count > 1)) {
- dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
- netif_wake_queue(fi->dev);
- }
- }
- }
- LEAVE("handle_OCI_interrupt");
- }
- /* Right now we discard OOO frames */
- static void handle_OOO_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry;
- int queue_indx, offset, payload_size;
- int no_of_buffers = 1; /* header is in a separate buffer */
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
- queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
- queue_indx = queue_indx >> 16;
- payload_size = ntohl(*(ptr_imq_entry + 2)) - TACHYON_HEADER_LEN;
- /* Calculate total number of buffers */
- no_of_buffers += payload_size / MFS_BUFFER_SIZE;
- if (payload_size % MFS_BUFFER_SIZE)
- no_of_buffers++;
- /* provide Tachyon will another set of buffers */
- fi->g.mfs_buffer_count += no_of_buffers;
- if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) {
- int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES;
- fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count;
- update_MFSBQ_indx(fi, count);
- }
- }
- static void handle_MFS_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry, *buff_addr;
- u_int type_of_frame, s_id;
- int queue_indx, offset, payload_size, starting_indx, starting_offset;
- u_short received_ox_id;
- int no_of_buffers = 1; /* header is in a separate buffer */
- struct sk_buff *skb;
- int wrap_around = FALSE, no_of_wrap_buffs = NO_OF_ENTRIES - 1;
- ENTER("handle_MFS_interrupt");
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
- queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
- queue_indx = queue_indx >> 16;
- DPRINTK("queue_indx = %d, offset = %dn", queue_indx, offset);
- payload_size = ntohl(*(ptr_imq_entry + 2)) - TACHYON_HEADER_LEN;
- DPRINTK("payload_size = %d", payload_size);
- /* Calculate total number of buffers */
- no_of_buffers += payload_size / MFS_BUFFER_SIZE;
- if (payload_size % MFS_BUFFER_SIZE)
- no_of_buffers++;
- DPRINTK("no_of_buffers = %d", no_of_buffers);
- if ((no_of_buffers - 1) <= offset) {
- starting_offset = offset - (no_of_buffers - 1);
- starting_indx = queue_indx;
- }
- else {
- int temp = no_of_buffers - (offset + 1);
- int no_of_queues = temp / NO_OF_ENTRIES;
- starting_offset = temp % NO_OF_ENTRIES;
- if (starting_offset != 0) {
- no_of_wrap_buffs = starting_offset - 1; //exclude header
- starting_offset = NO_OF_ENTRIES - starting_offset;
- no_of_queues++;
- }
- starting_indx = queue_indx - no_of_queues;
- if (starting_indx < 0) {
- no_of_wrap_buffs -= (starting_indx + 1) * NO_OF_ENTRIES;
- starting_indx = MFSBQ_LENGTH + starting_indx;
- wrap_around = TRUE;
- }
- }
-
- DPRINTK("starting_indx = %d, starting offset = %d no_of_wrap_buffs = %dn", starting_indx, starting_offset, no_of_wrap_buffs);
- /* Get Tachyon Header from first buffer */
- buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_mfsbq_base + starting_indx*NO_OF_ENTRIES + starting_offset)));
-
- /* extract Type of Frame */
- type_of_frame = (u_int)ntohl(*(buff_addr + 4)) & 0xFF000000;
- s_id = (u_int)ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
- received_ox_id = ntohl(*(buff_addr + 6)) >> 16;
- buff_addr += MFS_BUFFER_SIZE/4;
- DPRINTK("type_of_frame = %x, s_id = %x, ox_id = %x", type_of_frame, s_id, received_ox_id);
- switch(type_of_frame) {
- case TYPE_LLC_SNAP:
- skb = dev_alloc_skb(payload_size);
- if (skb == NULL) {
- printk(KERN_NOTICE "%s: In handle_MFS_interrupt() Memory squeeze, dropping packet.n", fi->name);
- fi->fc_stats.rx_dropped++;
- fi->g.mfs_buffer_count += no_of_buffers;
- if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) {
- int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES;
- fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count;
- update_MFSBQ_indx(fi, count);
- }
- return;
- }
- if (wrap_around) {
- int wrap_size = no_of_wrap_buffs * MFS_BUFFER_SIZE;
- int tail_size = payload_size - wrap_size;
- DPRINTK("wrap_size = %d, tail_size = %dn", wrap_size, tail_size);
- if (no_of_wrap_buffs)
- memcpy(skb_put(skb, wrap_size), buff_addr, wrap_size);
- buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_mfsbq_base)));
- memcpy(skb_put(skb, tail_size), buff_addr, tail_size);
- }
- else
- memcpy(skb_put(skb, payload_size), buff_addr, payload_size);
- rx_net_mfs_packet(fi, skb);
- break;
- default:
- T_MSG("Unknown Frame Type received. Type = %x", type_of_frame);
- }
- /* provide Tachyon will another set of buffers */
- fi->g.mfs_buffer_count += no_of_buffers;
- if (fi->g.mfs_buffer_count >= NO_OF_ENTRIES) {
- int count = fi->g.mfs_buffer_count / NO_OF_ENTRIES;
- fi->g.mfs_buffer_count -= NO_OF_ENTRIES * count;
- update_MFSBQ_indx(fi, count);
- }
- LEAVE("handle_MFS_interrupt");
- }
- static void handle_Unknown_Frame_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry;
- int queue_indx, offset;
- ENTER("handle_Unknown_Frame_interrupt");
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
- queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
- queue_indx = queue_indx >> 16;
- /* We discard the "unknown" frame */
- /* provide Tachyon will another set of buffers */
- if (offset == (NO_OF_ENTRIES - 1))
- update_SFSBQ_indx(fi);
- LEAVE("handle_Unknown_Frame_interrupt");
- }
- static void handle_Busied_Frame_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry;
- int queue_indx, offset;
- ENTER("handle_Busied_Frame_interrupt");
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
- queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
- queue_indx = queue_indx >> 16;
- /* We discard the "busied" frame */
- /* provide Tachyon will another set of buffers */
- if (offset == (NO_OF_ENTRIES - 1))
- update_SFSBQ_indx(fi);
- LEAVE("handle_Busied_Frame_interrupt");
- }
- static void handle_Bad_SCSI_Frame_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry, *buff_addr, *tach_header, *ptr_edb;
- u_int s_id, rctl, frame_class, burst_len, transfered_len, len = 0;
- int queue_indx, offset, payload_size, i;
- u_short ox_id, rx_id, x_id, mtu = 512;
- u_char target_id = 0xFF;
- ENTER("handle_Bad_SCSI_Frame_interrupt");
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
- queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
- queue_indx = queue_indx >> 16;
- payload_size = ntohl(*(ptr_imq_entry + 2));
- buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset)));
- rctl = ntohl(*(buff_addr + 2)) & 0xFF000000;
- s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
- ox_id = ntohl(*(buff_addr + 6)) >> 16;
- rx_id = ntohl(*(buff_addr + 6));
- x_id = ox_id & MAX_SCSI_XID;
- /* Any frame that comes in with OX_ID that matches an OX_ID
- * that has been allocated for SCSI, will be called a Bad
- * SCSI frame if the Exchange is not valid any more.
- *
- * We will also get a Bad SCSI frame interrupt if we receive
- * a XFER_RDY with offset != 0. Tachyon washes its hands off
- * this Exchange. We have to take care of ourselves. Grrr...
- */
- if (rctl == DATA_DESCRIPTOR) {
- struct fc_node_info *q = fi->node_info_list;
- while (q != NULL) {
- if (q->d_id == s_id) {
- target_id = q->target_id;
- mtu = q->mtu;
- break;
- }
- else
- q = q->next;
- }
- frame_class = target_id;
- transfered_len = ntohl(*(buff_addr + 8));
- burst_len = ntohl(*(buff_addr + 9));
- build_ODB(fi, fi->g.seq_id, s_id, burst_len, 0, mtu, ox_id, rx_id, 0, 0, frame_class << 16);
- /* Update the SEQ_ID and Relative Offset in the
- * Tachyon Header Structure.
- */
- tach_header = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 5)));
- *(tach_header + 5) = htonl(fi->g.seq_id << 24);
- *(tach_header + 7) = htonl(transfered_len);
- fi->g.odb.hdr_addr = *(fi->q.ptr_sest[x_id] + 5);
- /* Invalidate the EDBs used
- */
- ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7)));
- for (i = 0; i < EDB_LEN; i++)
- if (fi->q.ptr_edb[i] == ptr_edb)
- break;
- ptr_edb--;
-
- if (i < EDB_LEN) {
- int j;
- do {
- ptr_edb += 2;
- len += (htonl(*ptr_edb) & 0xFFFF);
- j = i;
- fi->q.free_edb_list[i++] = EDB_FREE;
- if (i == EDB_LEN) {
- i = 0;
- ptr_edb = fi->q.ptr_edb_base - 1;
- }
- } while (len < transfered_len);
- if (len > transfered_len) {
- ptr_edb--;
- fi->q.free_edb_list[j] = EDB_BUSY;
- }
- else
- ptr_edb++;
- }
- else {
- T_MSG("EDB not found while freeing");
- if (offset == (NO_OF_ENTRIES - 1))
- update_SFSBQ_indx(fi);
- return;
- }
- /* Update the EDB pointer in the ODB.
- */
- fi->g.odb.edb_addr = htonl(virt_to_bus(ptr_edb));
- memcpy(fi->q.ptr_odb[fi->q.ocq_prod_indx], &(fi->g.odb), sizeof(ODB));
- /* Update the EDB pointer in the SEST entry. We might need
- * this if get another XFER_RDY for the same Exchange.
- */
- *(fi->q.ptr_sest[x_id] + 7) = htonl(virt_to_bus(ptr_edb));
- update_OCQ_indx(fi);
- if (fi->g.seq_id == MAX_SEQ_ID)
- fi->g.seq_id = 0;
- else
- fi->g.seq_id++;
- }
- else
- /* Could be a BA_ACC or a BA_RJT.
- */
- if (rctl == RCTL_BASIC_ACC) {
- u_int bls_type = remove_from_ox_id_list(fi, ox_id);
- DPRINTK1("BA_ACC received from S_ID 0x%x with OX_ID = %x in response to %x", s_id, ox_id, bls_type);
- if (bls_type == RCTL_BASIC_ABTS) {
- u_int STE_bit;
- /* Invalidate resources for that Exchange.
- */
- STE_bit = ntohl(*fi->q.ptr_sest[x_id]);
- if (STE_bit & SEST_V) {
- *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV);
- invalidate_SEST_entry(fi, ox_id);
- }
- }
- }
- else
- if (rctl == RCTL_BASIC_RJT) {
- u_int bls_type = remove_from_ox_id_list(fi, ox_id);
- DPRINTK1("BA_RJT received from S_ID 0x%x with OX_ID = %x in response to %x", s_id, ox_id, bls_type);
- if (bls_type == RCTL_BASIC_ABTS) {
- u_int STE_bit;
- /* Invalidate resources for that Exchange.
- */
- STE_bit = ntohl(*fi->q.ptr_sest[x_id]);
- if (STE_bit & SEST_V) {
- *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV);
- invalidate_SEST_entry(fi, ox_id);
- }
- }
- }
- else
- DPRINTK1("Frame with R_CTL = %x received from S_ID 0x%x with OX_ID %x", rctl, s_id, ox_id);
- /* Else, discard the "Bad" SCSI frame.
- */
- /* provide Tachyon will another set of buffers
- */
- if (offset == (NO_OF_ENTRIES - 1))
- update_SFSBQ_indx(fi);
- LEAVE("handle_Bad_SCSI_Frame_interrupt");
- }
- static void handle_Inbound_SCSI_Status_interrupt(struct fc_info *fi)
- {
- struct Scsi_Host *host = fi->host;
- struct iph5526_hostdata *hostdata = (struct iph5526_hostdata *)host->hostdata;
- u_int *ptr_imq_entry, *buff_addr, *ptr_rsp_info, *ptr_sense_info = NULL;
- int queue_indx, offset, payload_size;
- u_short received_ox_id, x_id;
- Scsi_Cmnd *Cmnd;
- u_int fcp_status, fcp_rsp_info_len = 0, fcp_sense_info_len = 0, s_id;
- ENTER("handle_SCSI_status_interrupt");
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
- queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
- queue_indx = queue_indx >> 16;
- buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset)));
- payload_size = ntohl(*(ptr_imq_entry + 2));
- received_ox_id = ntohl(*(buff_addr + 6)) >> 16;
- buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset)));
- fcp_status = ntohl(*(buff_addr + 10));
- ptr_rsp_info = buff_addr + 14;
- if (fcp_status & FCP_STATUS_RSP_LEN)
- fcp_rsp_info_len = ntohl(*(buff_addr + 13));
-
- if (fcp_status & FCP_STATUS_SENSE_LEN) {
- ptr_sense_info = ptr_rsp_info + fcp_rsp_info_len / 4;
- fcp_sense_info_len = ntohl(*(buff_addr + 12));
- DPRINTK("sense_info = %x", (u_int)ntohl(*ptr_sense_info));
- }
- DPRINTK("fcp_status = %x, fcp_rsp_len = %x", fcp_status, fcp_rsp_info_len);
- x_id = received_ox_id & MAX_SCSI_XID;
- Cmnd = hostdata->cmnd_handler[x_id];
- hostdata->cmnd_handler[x_id] = NULL;
- if (Cmnd != NULL) {
- memset(Cmnd->sense_buffer, 0, sizeof(Cmnd->sense_buffer));
- /* Check if there is a Sense field */
- if (fcp_status & FCP_STATUS_SENSE_LEN) {
- int size = sizeof(Cmnd->sense_buffer);
- if (fcp_sense_info_len < size)
- size = fcp_sense_info_len;
- memcpy(Cmnd->sense_buffer, (char *)ptr_sense_info, size);
- }
- Cmnd->result = fcp_status & FCP_STATUS_MASK;
- (*Cmnd->scsi_done) (Cmnd);
- }
- else
- T_MSG("NULL Command out of handler!");
- invalidate_SEST_entry(fi, received_ox_id);
- s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
- fi->q.free_scsi_oxid[x_id] = OXID_AVAILABLE;
- /* provide Tachyon will another set of buffers */
- if (offset == (NO_OF_ENTRIES - 1))
- update_SFSBQ_indx(fi);
- LEAVE("handle_SCSI_status_interrupt");
- }
- static void invalidate_SEST_entry(struct fc_info *fi, u_short received_ox_id)
- {
- u_short x_id = received_ox_id & MAX_SCSI_XID;
- /* Invalidate SEST entry if it is an OutBound SEST Entry
- */
- if (!(received_ox_id & SCSI_READ_BIT)) {
- u_int *ptr_tach_header, *ptr_edb;
- u_short temp_ox_id = NOT_SCSI_XID;
- int i;
- *(fi->q.ptr_sest[x_id]) &= htonl(SEST_INV);
- /* Invalidate the Tachyon Header structure
- */
- ptr_tach_header = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 5)));
- for (i = 0; i < NO_OF_TACH_HEADERS; i++)
- if(fi->q.ptr_tachyon_header[i] == ptr_tach_header)
- break;
- if (i < NO_OF_TACH_HEADERS)
- memset(ptr_tach_header, 0xFF, 32);
- else
- T_MSG("Tachyon Header not found while freeing in invalidate_SEST_entry()");
- /* Invalidate the EDB used
- */
- ptr_edb = bus_to_virt(ntohl(*(fi->q.ptr_sest[x_id] + 7)));
- for (i = 0; i < EDB_LEN; i++)
- if (fi->q.ptr_edb[i] == ptr_edb)
- break;
- ptr_edb--;
- if (i < EDB_LEN) {
- do {
- ptr_edb += 2;
- fi->q.free_edb_list[i++] = EDB_FREE;
- if (i == EDB_LEN) {
- i = 0;
- ptr_edb = fi->q.ptr_edb_base - 1;
- }
- } while ((htonl(*ptr_edb) & 0x80000000) != 0x80000000);
- }
- else
- T_MSG("EDB not found while freeing in invalidate_SEST_entry()");
-
- /* Search for its other header structure and destroy it!
- */
- if ((ptr_tach_header + 16) < (fi->q.ptr_tachyon_header_base + (MY_PAGE_SIZE/4)))
- ptr_tach_header += 16;
- else
- ptr_tach_header = fi->q.ptr_tachyon_header_base;
- while (temp_ox_id != x_id) {
- temp_ox_id = ntohl(*(ptr_tach_header + 6)) >> 16;
- if (temp_ox_id == x_id) {
- /* Paranoid checking...
- */
- for (i = 0; i < NO_OF_TACH_HEADERS; i++)
- if(fi->q.ptr_tachyon_header[i] == ptr_tach_header)
- break;
- if (i < NO_OF_TACH_HEADERS)
- memset(ptr_tach_header, 0xFF, 32);
- else
- T_MSG("Tachyon Header not found while freeing in invalidate_SEST_entry()");
- break;
- }
- else {
- if ((ptr_tach_header + 16) < (fi->q.ptr_tachyon_header_base + (MY_PAGE_SIZE/4)))
- ptr_tach_header += 16;
- else
- ptr_tach_header = fi->q.ptr_tachyon_header_base;
- }
- }
- }
- else {
- u_short sdb_table_indx;
- /* An Inbound Command has completed or needs to be Aborted.
- * Clear up the SDB buffers.
- */
- sdb_table_indx = *(fi->q.ptr_sest[x_id] + 5);
- fi->q.sdb_slot_status[sdb_table_indx] = SDB_FREE;
- }
- }
- static void handle_Inbound_SCSI_Command_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry;
- int queue_indx, offset;
- ENTER("handle_Inbound_SCSI_Command_interrupt");
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
- queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
- queue_indx = queue_indx >> 16;
- /* We discard the SCSI frame as we shouldn't be receiving
- * a SCSI Command in the first place
- */
- /* provide Tachyon will another set of buffers */
- if (offset == (NO_OF_ENTRIES - 1))
- update_SFSBQ_indx(fi);
- LEAVE("handle_Inbound_SCSI_Command_interrupt");
- }
- static void handle_SFS_interrupt(struct fc_info *fi)
- {
- u_int *ptr_imq_entry, *buff_addr;
- u_int class_of_frame, type_of_frame, s_id, els_type = 0, rctl;
- int queue_indx, offset, payload_size, login_state;
- u_short received_ox_id, fs_cmnd_code;
- ENTER("handle_SFS_interrupt");
- ptr_imq_entry = fi->q.ptr_imqe[fi->q.imq_cons_indx];
- offset = ntohl(*(ptr_imq_entry + 1)) & 0x00000007;
- queue_indx = ntohl(*(ptr_imq_entry + 1)) & 0xFFFF0000;
- queue_indx = queue_indx >> 16;
- DPRINTK("queue_indx = %d, offset = %dn", queue_indx, offset);
- payload_size = ntohl(*(ptr_imq_entry + 2));
- DPRINTK("payload_size = %d", payload_size);
- buff_addr = bus_to_virt(ntohl(*(fi->q.ptr_sfsbq_base + queue_indx*NO_OF_ENTRIES + offset)));
- /* extract Type of Frame */
- type_of_frame = ntohl(*(buff_addr + 4)) & 0xFF000000;
- s_id = ntohl(*(buff_addr + 3)) & 0x00FFFFFF;
- received_ox_id = ntohl(*(buff_addr + 6)) >> 16;
- switch(type_of_frame) {
- case TYPE_BLS:
- rctl = ntohl(*(buff_addr + 2)) & 0xFF000000;
- switch(rctl) {
- case RCTL_BASIC_ABTS:
- /* As an Initiator, we should never be receiving
- * this.
- */
- DPRINTK1("ABTS received from S_ID 0x%x with OX_ID = %x", s_id, received_ox_id);
- break;
- }
- break;
- case TYPE_ELS:
- class_of_frame = ntohl(*(buff_addr + 8));
- login_state = sid_logged_in(fi, s_id);
- switch(class_of_frame & 0xFF000000) {
- case ELS_PLOGI:
- if (s_id != fi->g.my_id) {
- u_int ret_code;
- DPRINTK1("PLOGI received from D_ID 0x%x with 0X_ID = %x", s_id, received_ox_id);
- if ((ret_code = plogi_ok(fi, buff_addr, payload_size)) == 0){
- tx_logi_acc(fi, ELS_ACC, s_id, received_ox_id);
- add_to_address_cache(fi, buff_addr);
- }
- else {
- u_short cmnd_code = ret_code >> 16;
- u_short expln_code = ret_code;
- tx_ls_rjt(fi, s_id, received_ox_id, cmnd_code, expln_code);
- }
- }
- break;
- case ELS_ACC:
- els_type = remove_from_ox_id_list(fi, received_ox_id);
- DPRINTK1("ELS_ACC received from D_ID 0x%x in response to ELS %x", s_id, els_type);
- switch(els_type) {
- case ELS_PLOGI:
- add_to_address_cache(fi, buff_addr);
- tx_prli(fi, ELS_PRLI, s_id, OX_ID_FIRST_SEQUENCE);
- break;
- case ELS_FLOGI:
- add_to_address_cache(fi, buff_addr);
- fi->g.my_id = ntohl(*(buff_addr + 2)) & 0x00FFFFFF;
- fi->g.fabric_present = TRUE;
- fi->g.my_ddaa = fi->g.my_id & 0xFFFF00;
- /* Login to the Name Server
- */
- tx_logi(fi, ELS_PLOGI, DIRECTORY_SERVER);
- break;
- case ELS_NS_PLOGI:
- fi->g.name_server = TRUE;
- add_to_address_cache(fi, buff_addr);
- tx_name_server_req(fi, FCS_RFC_4);
- tx_scr(fi);
- /* Some devices have a delay before
- * registering with the Name Server
- */
- udelay(500);
- tx_name_server_req(fi, FCS_GP_ID4);
- break;
- case ELS_PRLI:
- mark_scsi_sid(fi, buff_addr, ADD_ENTRY);
- break;
- case ELS_ADISC:
- if (!(validate_login(fi, buff_addr)))
- tx_logo(fi, s_id, OX_ID_FIRST_SEQUENCE);
- break;
- }
- break;
- case ELS_PDISC:
- DPRINTK1("ELS_PDISC received from D_ID 0x%x", s_id);
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_ADISC:
- DPRINTK1("ELS_ADISC received from D_ID 0x%x", s_id);
- if (node_logged_in_prev(fi, buff_addr))
- tx_adisc(fi, ELS_ACC, s_id, received_ox_id);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_PRLI:
- DPRINTK1("ELS_PRLI received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN)) {
- tx_prli(fi, ELS_ACC, s_id, received_ox_id);
- mark_scsi_sid(fi, buff_addr, ADD_ENTRY);
- }
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_PRLO:
- DPRINTK1("ELS_PRLO received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_OUT) || (login_state == NODE_NOT_PRESENT))
- tx_logo(fi, s_id, received_ox_id);
- else
- if (login_state == NODE_LOGGED_IN)
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- if (login_state == NODE_PROCESS_LOGGED_IN) {
- tx_prli(fi, ELS_ACC, s_id, received_ox_id);
- mark_scsi_sid(fi, buff_addr, DELETE_ENTRY);
- }
- break;
- case ELS_LS_RJT:
- els_type = remove_from_ox_id_list(fi, received_ox_id);
- DPRINTK1("ELS_LS_RJT received from D_ID 0x%x in response to %x", s_id, els_type);
- /* We should be chking the reason code.
- */
- switch (els_type) {
- case ELS_ADISC:
- tx_logi(fi, ELS_PLOGI, s_id);
- break;
- }
- break;
- case ELS_LOGO:
- els_type = remove_from_ox_id_list(fi, received_ox_id);
- DPRINTK1("ELS_LOGO received from D_ID 0x%x in response to %x", s_id, els_type);
- remove_from_address_cache(fi, buff_addr, ELS_LOGO);
- tx_acc(fi, s_id, received_ox_id);
- if (els_type == ELS_ADISC)
- tx_logi(fi, ELS_PLOGI, s_id);
- break;
- case ELS_RSCN:
- DPRINTK1("ELS_RSCN received from D_ID 0x%x", s_id);
- tx_acc(fi, s_id, received_ox_id);
- remove_from_address_cache(fi, buff_addr, ELS_RSCN);
- break;
- case ELS_FARP_REQ:
- /* We do not support FARP.
- So, silently discard it */
- DPRINTK1("ELS_FARP_REQ received from D_ID 0x%x", s_id);
- break;
- case ELS_ABTX:
- DPRINTK1("ELS_ABTX received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_FLOGI:
- DPRINTK1("ELS_FLOGI received from D_ID 0x%x", s_id);
- if (fi->g.ptp_up == TRUE) {
- /* The node could have come up as an N_Port
- * in a Loop! So,try initializing as an NL_port
- */
- take_tachyon_offline(fi);
- /* write AL_TIME & E_D_TOV into the registers */
- writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
- writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg);
- DPRINTK1("FLOGI received, TACHYON initializing as L_Port...n");
- writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
- }
- else {
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- }
- break;
- case ELS_ADVC:
- DPRINTK1("ELS_ADVC received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_ECHO:
- DPRINTK1("ELS_ECHO received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_ESTC:
- DPRINTK1("ELS_ESTC received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_ESTS:
- DPRINTK1("ELS_ESTS received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_RCS:
- DPRINTK1("ELS_RCS received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_RES:
- DPRINTK1("ELS_RES received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_RLS:
- DPRINTK1("ELS_RLS received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_RRQ:
- DPRINTK1("ELS_RRQ received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_RSS:
- DPRINTK1("ELS_RSS received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_RTV:
- DPRINTK1("ELS_RTV received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_RSI:
- DPRINTK1("ELS_RSI received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_TEST:
- /* No reply sequence */
- DPRINTK1("ELS_TEST received from D_ID 0x%x", s_id);
- break;
- case ELS_RNC:
- DPRINTK1("ELS_RNC received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_RVCS:
- DPRINTK1("ELS_RVCS received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_TPLS:
- DPRINTK1("ELS_TPLS received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_GAID:
- DPRINTK1("ELS_GAID received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_FACT:
- DPRINTK1("ELS_FACT received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_FAN:
- /* Hmmm... You don't support FAN ??? */
- DPRINTK1("ELS_FAN received from D_ID 0x%x", s_id);
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- break;
- case ELS_FDACT:
- DPRINTK1("ELS_FDACT received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_NACT:
- DPRINTK1("ELS_NACT received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_NDACT:
- DPRINTK1("ELS_NDACT received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_QoSR:
- DPRINTK1("ELS_QoSR received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- case ELS_FDISC:
- DPRINTK1("ELS_FDISC received from D_ID 0x%x", s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- default:
- DPRINTK1("ELS Frame %x received from D_ID 0x%x", class_of_frame, s_id);
- if ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN))
- tx_ls_rjt(fi, s_id, received_ox_id, CMND_NOT_SUPP, NO_EXPLN);
- else
- tx_logo(fi, s_id, received_ox_id);
- break;
- }
- break;
- case TYPE_FC_SERVICES:
- fs_cmnd_code = (ntohl(*(buff_addr + 10)) & 0xFFFF0000) >>16;
- switch(fs_cmnd_code) {
- case FCS_ACC:
- els_type = remove_from_ox_id_list(fi, received_ox_id);
- DPRINTK1("FCS_ACC received from D_ID 0x%x in response to %x", s_id, els_type);
- if (els_type == FCS_GP_ID4)
- explore_fabric(fi, buff_addr);
- break;
- case FCS_REJECT:
- DPRINTK1("FCS_REJECT received from D_ID 0x%x in response to %x", s_id, els_type);
- break;
- }
- break;
- case TYPE_LLC_SNAP:
- rx_net_packet(fi, (u_char *)buff_addr, payload_size);
- break;
- default:
- T_MSG("Frame Type %x received from %x", type_of_frame, s_id);
- }
- /* provide Tachyon will another set of buffers */
- if (offset == (NO_OF_ENTRIES - 1))
- update_SFSBQ_indx(fi);
- LEAVE("handle_SFS_interrupt");
- }
- static void handle_FM_interrupt(struct fc_info *fi)
- {
- u_int fm_status;
- u_int tachyon_status;
- ENTER("handle_FM_interrupt");
- fm_status = readl(fi->t_r.ptr_fm_status_reg);
- tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
- DPRINTK("FM_status = %x, Tachyon_status = %x", fm_status, tachyon_status);
- if (fm_status & LINK_DOWN) {
- T_MSG("Fibre Channel Link DOWN");
- fm_status = readl(fi->t_r.ptr_fm_status_reg);
-
- del_timer(&fi->explore_timer);
- del_timer(&fi->nport_timer);
- del_timer(&fi->lport_timer);
- del_timer(&fi->display_cache_timer);
- fi->g.link_up = FALSE;
- if (fi->g.ptp_up == TRUE)
- fi->g.n_port_try = FALSE;
- fi->g.ptp_up = FALSE;
- fi->g.port_discovery = FALSE;
- fi->g.explore_fabric = FALSE;
- fi->g.perform_adisc = FALSE;
- /* Logout will all nodes */
- if (fi->node_info_list) {
- struct fc_node_info *temp_list = fi->node_info_list;
- while(temp_list) {
- temp_list->login = LOGIN_ATTEMPTED;
- temp_list = temp_list->next;
- }
- fi->num_nodes = 0;
- }
- if ((fi->g.n_port_try == FALSE) && (fi->g.dont_init == FALSE)){
- take_tachyon_offline(fi);
- /* write AL_TIME & E_D_TOV into the registers */
- writel(TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
-
- if ((fi->g.fabric_present == TRUE) && (fi->g.loop_up == TRUE)) {
- u_int al_pa = fi->g.my_id & 0xFF;
- writel((al_pa << 24) | LOOP_INIT_FABRIC_ADDRESS | LOOP_INIT_PREVIOUS_ADDRESS, fi->t_r.ptr_fm_config_reg);
- }
- else
- if (fi->g.loop_up == TRUE) {
- u_int al_pa = fi->g.my_id & 0xFF;
- writel((al_pa << 24) | LOOP_INIT_PREVIOUS_ADDRESS, fi->t_r.ptr_fm_config_reg);
- }
- else
- writel(LOOP_INIT_SOFT_ADDRESS, fi->t_r.ptr_fm_config_reg);
- fi->g.loop_up = FALSE;
- DPRINTK1("In LDWN TACHYON initializing as L_Port...n");
- writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
- }
- }
- if (fm_status & NON_PARTICIPATING) {
- T_MSG("Did not acquire an AL_PA. I am not participating");
- }
- else
- if ((fm_status & LINK_UP) && ((fm_status & LINK_DOWN) == 0)) {
- T_MSG("Fibre Channel Link UP");
- if ((fm_status & NON_PARTICIPATING) != TRUE) {
- fi->g.link_up = TRUE;
- if (tachyon_status & OSM_FROZEN) {
- reset_tachyon(fi, ERROR_RELEASE);
- reset_tachyon(fi, OCQ_RESET);
- }
- init_timer(&fi->explore_timer);
- init_timer(&fi->nport_timer);
- init_timer(&fi->lport_timer);
- init_timer(&fi->display_cache_timer);
- if ((fm_status & OLD_PORT) == 0) {
- fi->g.loop_up = TRUE;
- fi->g.ptp_up = FALSE;
- fi->g.my_id = readl(fi->t_r.ptr_fm_config_reg) >> 24;
- DPRINTK1("My AL_PA = %x", fi->g.my_id);
- fi->g.port_discovery = TRUE;
- fi->g.explore_fabric = FALSE;
- }
- else
- if (((fm_status & 0xF0) == OLD_PORT) && ((fm_status & 0x0F) == PORT_STATE_ACTIVE)) {
- fi->g.loop_up = FALSE;
- fi->g.my_id = 0x0;
- /* In a point-to-point configuration, we expect to be
- * connected to an F_Port. This driver does not yet support
- * a configuration where it is connected to another N_Port
- * directly.
- */
- fi->g.explore_fabric = TRUE;
- fi->g.port_discovery = FALSE;
- if (fi->g.n_port_try == FALSE) {
- take_tachyon_offline(fi);
- /* write R_T_TOV & E_D_TOV into the registers */
- writel(PTP_TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
- writel(BB_CREDIT | NPORT, fi->t_r.ptr_fm_config_reg);
- fi->g.n_port_try = TRUE;
- DPRINTK1("In LUP TACHYON initializing as N_Port...n");
- writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
- }
- else {
- fi->g.ptp_up = TRUE;
- tx_logi(fi, ELS_FLOGI, F_PORT);
- }
- }
- fi->g.my_ddaa = 0x0;
- fi->g.fabric_present = FALSE;
- /* We havn't sent out any Name Server Reqs */
- fi->g.name_server = FALSE;
- fi->g.alpa_list_index = 0;
- fi->g.ox_id = NOT_SCSI_XID;
- fi->g.my_mtu = TACH_FRAME_SIZE;
-
- /* Implicitly LOGO with all logged-in nodes.
- */
- if (fi->node_info_list) {
- struct fc_node_info *temp_list = fi->node_info_list;
- while(temp_list) {
- temp_list->login = LOGIN_ATTEMPTED;
- temp_list = temp_list->next;
- }
- fi->num_nodes = 0;
- fi->g.perform_adisc = TRUE;
- //fi->g.perform_adisc = FALSE;
- fi->g.port_discovery = FALSE;
- tx_logi(fi, ELS_FLOGI, F_PORT);
- }
- else {
- /* If Link coming up for the _first_ time or no nodes
- * were logged in before...
- */
- fi->g.scsi_oxid = 0;
- fi->g.seq_id = 0x00;
- fi->g.perform_adisc = FALSE;
- }
- /* reset OX_ID table */
- while (fi->ox_id_list) {
- struct ox_id_els_map *temp = fi->ox_id_list;
- fi->ox_id_list = fi->ox_id_list->next;
- kfree(temp);
- }
- fi->ox_id_list = NULL;
- } /* End of if partipating */
- }
- if (fm_status & ELASTIC_STORE_ERROR) {
- /* Too much junk on the Link
- */
- /* Trying to clear it up by Txing PLOGI to urself */
- if (fi->g.link_up == TRUE)
- tx_logi(fi, ELS_PLOGI, fi->g.my_id);
- }
- if (fm_status & LOOP_UP) {
- if (tachyon_status & OSM_FROZEN) {
- reset_tachyon(fi, ERROR_RELEASE);
- reset_tachyon(fi, OCQ_RESET);
- }
- }
-
- if (fm_status & NOS_OLS_RECEIVED){
- if (fi->g.nport_timer_set == FALSE) {
- DPRINTK("NOS/OLS Received");
- DPRINTK("FM_status = %x", fm_status);
- fi->nport_timer.function = nos_ols_timer;
- fi->nport_timer.data = (unsigned long)fi;
- fi->nport_timer.expires = RUN_AT((3*HZ)/100); /* 30 msec */
- init_timer(&fi->nport_timer);
- add_timer(&fi->nport_timer);
- fi->g.nport_timer_set = TRUE;
- }
- }
- if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_LF1) || ((fm_status & 0x0F) == PORT_STATE_LF2))) {
- DPRINTK1("Link Fail-I in OLD-PORT.");
- take_tachyon_offline(fi);
- reset_tachyon(fi, SOFTWARE_RESET);
- }
- if (fm_status & LOOP_STATE_TIMEOUT){
- if ((fm_status & 0xF0) == ARBITRATING)
- DPRINTK1("ED_TOV timesout.In ARBITRATING state...");
- if ((fm_status & 0xF0) == ARB_WON)
- DPRINTK1("ED_TOV timesout.In ARBITRATION WON state...");
- if ((fm_status & 0xF0) == OPEN)
- DPRINTK1("ED_TOV timesout.In OPEN state...");
- if ((fm_status & 0xF0) == OPENED)
- DPRINTK1("ED_TOV timesout.In OPENED state...");
- if ((fm_status & 0xF0) == TX_CLS)
- DPRINTK1("ED_TOV timesout.In XMITTED CLOSE state...");
- if ((fm_status & 0xF0) == RX_CLS)
- DPRINTK1("ED_TOV timesout.In RECEIVED CLOSE state...");
- if ((fm_status & 0xF0) == INITIALIZING)
- DPRINTK1("ED_TOV timesout.In INITIALIZING state...");
- DPRINTK1("Initializing Loop...");
- writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
- }
-
- if ((fm_status & BAD_ALPA) && (fi->g.loop_up == TRUE)) {
- u_char bad_alpa = (readl(fi->t_r.ptr_fm_rx_al_pa_reg) & 0xFF00) >> 8;
- if (tachyon_status & OSM_FROZEN) {
- reset_tachyon(fi, ERROR_RELEASE);
- reset_tachyon(fi, OCQ_RESET);
- }
- /* Fix for B34 */
- tx_logi(fi, ELS_PLOGI, fi->g.my_id);
- if (!fi->g.port_discovery && !fi->g.perform_adisc) {
- if (bad_alpa != 0xFE)
- DPRINTK("Bad AL_PA = %x", bad_alpa);
- }
- else {
- if ((fi->g.perform_adisc == TRUE) && (bad_alpa == 0x00)) {
- DPRINTK1("Performing ADISC...");
- fi->g.fabric_present = FALSE;
- perform_adisc(fi);
- }
- }
- }
-
- if (fm_status & LIPF_RECEIVED){
- DPRINTK("LIP(F8) Received");
- }
- if (fm_status & LINK_FAILURE) {
- if (fm_status & LOSS_OF_SIGNAL)
- DPRINTK1("Detected Loss of Signal.");
- if (fm_status & OUT_OF_SYNC)
- DPRINTK1("Detected Loss of Synchronization.");
- }
- if (fm_status & TRANSMIT_PARITY_ERROR) {
- /* Bad! Should not happen. Solution-> Hard Reset.
- */
- T_MSG("Parity Error. Perform Hard Reset!");
- }
- if (fi->g.alpa_list_index >= MAX_NODES){
- if (fi->g.port_discovery == TRUE) {
- fi->g.port_discovery = FALSE;
- add_display_cache_timer(fi);
- }
- fi->g.alpa_list_index = MAX_NODES;
- }
- if (fi->g.port_discovery == TRUE)
- local_port_discovery(fi);
- LEAVE("handle_FM_interrupt");
- return;
- }
- static void local_port_discovery(struct fc_info *fi)
- {
- if (fi->g.loop_up == TRUE) {
- /* If this is not here, some of the Bad AL_PAs are missed.
- */
- udelay(20);
- if ((fi->g.alpa_list_index == 0) && (fi->g.fabric_present == FALSE)){
- tx_logi(fi, ELS_FLOGI, F_PORT);
- }
- else {
- int login_state = sid_logged_in(fi, fi->g.my_ddaa | alpa_list[fi->g.alpa_list_index]);
- while ((fi->g.alpa_list_index == 0) || ((fi->g.alpa_list_index < MAX_NODES) && ((login_state == NODE_LOGGED_IN) || (login_state == NODE_PROCESS_LOGGED_IN) || (alpa_list[fi->g.alpa_list_index] == (fi->g.my_id & 0xFF)))))
- fi->g.alpa_list_index++;
- if (fi->g.alpa_list_index < MAX_NODES)
- tx_logi(fi, ELS_PLOGI, alpa_list[fi->g.alpa_list_index]);
- }
- fi->g.alpa_list_index++;
- if (fi->g.alpa_list_index >= MAX_NODES){
- if (fi->g.port_discovery == TRUE) {
- fi->g.port_discovery = FALSE;
- add_display_cache_timer(fi);
- }
- fi->g.alpa_list_index = MAX_NODES;
- }
- }
- }
- static void nos_ols_timer(unsigned long data)
- {
- struct fc_info *fi = (struct fc_info*)data;
- u_int fm_status;
- fm_status = readl(fi->t_r.ptr_fm_status_reg);
- DPRINTK1("FM_status in timer= %x", fm_status);
- fi->g.nport_timer_set = FALSE;
- del_timer(&fi->nport_timer);
- if ((fi->g.ptp_up == TRUE) || (fi->g.loop_up == TRUE))
- return;
- if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_ACTIVE) || ((fm_status & 0x0F) == PORT_STATE_OFFLINE))) {
- DPRINTK1("In OLD-PORT after E_D_TOV.");
- take_tachyon_offline(fi);
- /* write R_T_TOV & E_D_TOV into the registers */
- writel(PTP_TOV_VALUES, fi->t_r.ptr_fm_tov_reg);
- writel(BB_CREDIT | NPORT, fi->t_r.ptr_fm_config_reg);
- fi->g.n_port_try = TRUE;
- DPRINTK1("In timer, TACHYON initializing as N_Port...n");
- writel(INITIALIZE, fi->t_r.ptr_fm_control_reg);
- }
- else
- if ((fi->g.lport_timer_set == FALSE) && ((fm_status & 0xF0) == LOOP_FAIL)) {
- DPRINTK1("Loop Fail after E_D_TOV.");
- fi->lport_timer.function = loop_timer;
- fi->lport_timer.data = (unsigned long)fi;
- fi->lport_timer.expires = RUN_AT((8*HZ)/100);
- init_timer(&fi->lport_timer);
- add_timer(&fi->lport_timer);
- fi->g.lport_timer_set = TRUE;
- take_tachyon_offline(fi);
- reset_tachyon(fi, SOFTWARE_RESET);
- }
- else
- if (((fm_status & 0xF0) == OLD_PORT) && (((fm_status & 0x0F) == PORT_STATE_LF1) || ((fm_status & 0x0F) == PORT_STATE_LF2))) {
- DPRINTK1("Link Fail-II in OLD-PORT.");
- take_tachyon_offline(fi);
- reset_tachyon(fi, SOFTWARE_RESET);
- }
- }
- static void loop_timer(unsigned long data)
- {
- struct fc_info *fi = (struct fc_info*)data;
- fi->g.lport_timer_set = FALSE;
- del_timer(&fi->lport_timer);
- if ((fi->g.ptp_up == TRUE) || (fi->g.loop_up == TRUE))
- return;
- }
- static void add_display_cache_timer(struct fc_info *fi)
- {
- fi->display_cache_timer.function = display_cache_timer;
- fi->display_cache_timer.data = (unsigned long)fi;
- fi->display_cache_timer.expires = RUN_AT(fi->num_nodes * HZ);
- init_timer(&fi->display_cache_timer);
- add_timer(&fi->display_cache_timer);
- }
- static void display_cache_timer(unsigned long data)
- {
- struct fc_info *fi = (struct fc_info*)data;
- del_timer(&fi->display_cache_timer);
- display_cache(fi);
- return;
- }
- static void reset_tachyon(struct fc_info *fi, u_int value)
- {
- u_int tachyon_status, reset_done = OCQ_RESET_STATUS | SCSI_FREEZE_STATUS;
- int not_done = 1, i = 0;
- writel(value, fi->t_r.ptr_tach_control_reg);
- if (value == OCQ_RESET)
- fi->q.ocq_prod_indx = 0;
- tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
- /* Software resets are immediately done, whereas other aren't. It
- about 30 clocks to do the reset */
- if (value != SOFTWARE_RESET) {
- while(not_done) {
- if (i++ > 100000) {
- T_MSG("Reset was unsuccessful! Tachyon Status = %x", tachyon_status);
- break;
- }
- tachyon_status = readl(fi->t_r.ptr_tach_status_reg);
- if ((tachyon_status & reset_done) == 0)
- not_done = 0;
- }
- }
- else {
- write_to_tachyon_registers(fi);
- }
- }
- static void take_tachyon_offline(struct fc_info *fi)
- {
- u_int fm_status = readl(fi->t_r.ptr_fm_status_reg);
- /* The first two conditions will never be true. The Manual and
- * the errata say this. But the current implementation is
- * decently stable.
- */
- //if ((fm_status & 0xF0) == LOOP_FAIL) {
- if (fm_status == LOOP_FAIL) {
- // workaround as in P. 89
- writel(HOST_CONTROL, fi->t_r.ptr_fm_control_reg);
- if (fi->g.loop_up == TRUE)
- writel(SOFTWARE_RESET, fi->t_r.ptr_tach_control_reg);
- else {
- writel(OFFLINE, fi->t_r.ptr_fm_control_reg);
- writel(EXIT_HOST_CONTROL, fi->t_r.ptr_fm_control_reg);
- }
- }
- else
- //if ((fm_status & LOOP_UP) == LOOP_UP) {
- if (fm_status == LOOP_UP) {
- writel(SOFTWARE_RESET, fi->t_r.ptr_tach_control_reg);
- }
- else
- writel(OFFLINE, fi->t_r.ptr_fm_control_reg);
- }
- static void read_novram(struct fc_info *fi)
- {
- int off = 0;
- fi->n_r.ptr_novram_hw_control_reg = fi->i_r.ptr_ichip_hw_control_reg;
- fi->n_r.ptr_novram_hw_status_reg = fi->i_r.ptr_ichip_hw_status_reg;
- iph5526_nr_do_init(fi);
- if (fi->clone_id == PCI_VENDOR_ID_INTERPHASE)
- off = 32;
-
- fi->g.my_node_name_high = (fi->n_r.data[off] << 16) | fi->n_r.data[off+1];
- fi->g.my_node_name_low = (fi->n_r.data[off+2] << 16) | fi->n_r.data[off+3];
- fi->g.my_port_name_high = (fi->n_r.data[off+4] << 16) | fi->n_r.data[off+5];
- fi->g.my_port_name_low = (fi->n_r.data[off+6] << 16) | fi->n_r.data[off+7];
- DPRINTK("node_name = %x %x", fi->g.my_node_name_high, fi->g.my_node_name_low);
- DPRINTK("port_name = %x %x", fi->g.my_port_name_high, fi->g.my_port_name_low);
- }
- static void reset_ichip(struct fc_info *fi)
- {
- /* (i)chip reset */
- writel(ICHIP_HCR_RESET, fi->i_r.ptr_ichip_hw_control_reg);
- /*wait for chip to get reset */
- mdelay(10);
- /*de-assert reset */
- writel(ICHIP_HCR_DERESET, fi->i_r.ptr_ichip_hw_control_reg);
-
- /* enable INT lines on the (i)chip */
- writel(ICHIP_HCR_ENABLE_INTA , fi->i_r.ptr_ichip_hw_control_reg);
- /* enable byte swap */
- writel(ICHIP_HAMR_BYTE_SWAP_ADDR_TR, fi->i_r.ptr_ichip_hw_addr_mask_reg);
- }
- static void tx_logi(struct fc_info *fi, u_int logi, u_int d_id)
- {
- int int_required = 1;
- u_short ox_id = OX_ID_FIRST_SEQUENCE;
- u_int r_ctl = RCTL_ELS_UCTL;
- u_int type = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE;
- u_int my_mtu = fi->g.my_mtu;
- ENTER("tx_logi");
- /* We dont want interrupted for our own logi.
- * It screws up the port discovery process.
- */
- if (d_id == fi->g.my_id)
- int_required = 0;
- fill_login_frame(fi, logi);
- fi->g.type_of_frame = FC_ELS;
- memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.login, sizeof(LOGIN));
- tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),sizeof(LOGIN), r_ctl, type, d_id, my_mtu, int_required, ox_id, logi);
- fi->g.e_i++;
- if (fi->g.e_i == MAX_PENDING_FRAMES)
- fi->g.e_i = 0;
- LEAVE("tx_logi");
- return;
- }
- static void tx_logi_acc(struct fc_info *fi, u_int logi, u_int d_id, u_short received_ox_id)
- {
- int int_required = 0;
- u_int r_ctl = RCTL_ELS_SCTL;
- u_int type = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE;
- u_int my_mtu = fi->g.my_mtu;
- ENTER("tx_logi_acc");
- fill_login_frame(fi, logi);
- fi->g.type_of_frame = FC_ELS;
- memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.login, sizeof(LOGIN));
- tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),sizeof(LOGIN), r_ctl, type, d_id, my_mtu, int_required, received_ox_id, logi);
- fi->g.e_i++;
- if (fi->g.e_i == MAX_PENDING_FRAMES)
- fi->g.e_i = 0;
- LEAVE("tx_logi_acc");
- return;
- }
- static void tx_prli(struct fc_info *fi, u_int command_code, u_int d_id, u_short received_ox_id)
- {
- int int_required = 1;
- u_int r_ctl = RCTL_ELS_UCTL;
- u_int type = TYPE_ELS | SEQUENCE_INITIATIVE | FIRST_SEQUENCE;
- u_int my_mtu = fi->g.my_mtu;
- ENTER("tx_prli");
- if (command_code == ELS_PRLI)
- fi->g.prli.cmnd_code = htons((ELS_PRLI | PAGE_LEN) >> 16);
- else {
- fi->g.prli.cmnd_code = htons((ELS_ACC | PAGE_LEN) >> 16);
- int_required = 0;
- type = TYPE_ELS | EXCHANGE_RESPONDER | LAST_SEQUENCE;
- r_ctl = RCTL_ELS_SCTL;
- }
- fi->g.prli.payload_length = htons(PRLI_LEN);
- fi->g.prli.type_code = htons(FCP_TYPE_CODE);
- fi->g.prli.est_image_pair = htons(IMAGE_PAIR);
- fi->g.prli.responder_pa = 0;
- fi->g.prli.originator_pa = 0;
- fi->g.prli.service_params = htonl(INITIATOR_FUNC | READ_XFER_RDY_DISABLED);
- fi->g.type_of_frame = FC_ELS;
- memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.prli, sizeof(PRLI));
- tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]), sizeof(PRLI), r_ctl, type, d_id, my_mtu, int_required, received_ox_id, command_code);
- fi->g.e_i++;
- if (fi->g.e_i == MAX_PENDING_FRAMES)
- fi->g.e_i = 0;
- LEAVE("tx_prli");
- return;
- }
- static void tx_logo(struct fc_info *fi, u_int d_id, u_short received_ox_id)
- {
- int int_required = 1;
- u_int r_ctl = RCTL_ELS_UCTL;
- u_int type = TYPE_ELS | EXCHANGE_RESPONDER | SEQUENCE_RESPONDER | FIRST_SEQUENCE | END_SEQUENCE | SEQUENCE_INITIATIVE;
- int size = sizeof(LOGO);
- char fc_id[3];
- u_int my_mtu = fi->g.my_mtu;
- ENTER("tx_logo");
- fi->g.logo.logo_cmnd = htonl(ELS_LOGO);
- fi->g.logo.reserved = 0;
- memcpy(fc_id, &(fi->g.my_id), 3);
- fi->g.logo.n_port_id_0 = fc_id[0];
- fi->g.logo.n_port_id_1 = fc_id[1];
- fi->g.logo.n_port_id_2 = fc_id[2];
- fi->g.logo.port_name_up = htonl(N_PORT_NAME_HIGH);
- fi->g.logo.port_name_low = htonl(N_PORT_NAME_LOW);
- fi->g.type_of_frame = FC_ELS;
- memcpy(fi->g.els_buffer[fi->g.e_i], &fi->g.logo, sizeof(LOGO));
- tx_exchange(fi, (char *)(fi->g.els_buffer[fi->g.e_i]),size, r_ctl, type, d_id, my_mtu, int_required, received_ox_id, ELS_LOGO);
- fi->g.e_i++;
- if (fi->g.e_i == MAX_PENDING_FRAMES)
- fi->g.e_i = 0;