📄 dpt_i2o.c
字号:
/*************************************************************************** dpti.c - description ------------------- begin : Thu Sep 7 2000 copyright : (C) 2000 by Adaptec email : deanna_bonds@adaptec.com July 30, 2001 First version being submitted for inclusion in the kernel. V2.4 See README.dpti for history, notes, license info, and credits ***************************************************************************//*************************************************************************** * * * 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 of the License, or * * (at your option) any later version. * * * ***************************************************************************///#define DEBUG 1//#define UARTDELAY 1// On the real kernel ADDR32 should always be zero for 2.4. GFP_HIGH allocates// high pages. Keep the macro around because of the broken unmerged ia64 tree#define ADDR32 (0)#include <linux/version.h>#include <linux/module.h>MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");MODULE_DESCRIPTION("Adaptec I2O RAID Driver");////////////////////////////////////////////////////////////////#include <linux/ioctl.h> /* For SCSI-Passthrough */#include <asm/uaccess.h>#include <linux/stat.h>#include <linux/slab.h> /* for kmalloc() */#include <linux/config.h> /* for CONFIG_PCI */#include <linux/pci.h> /* for PCI support */#include <linux/proc_fs.h>#include <linux/blk.h>#include <linux/delay.h> /* for udelay */#include <linux/tqueue.h>#include <linux/interrupt.h>#include <linux/kernel.h> /* for printk */#include <linux/sched.h>#include <linux/reboot.h>#include <linux/smp_lock.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/ioport.h>#include <linux/stat.h>#include <asm/processor.h> /* for boot_cpu_data */#include <asm/pgtable.h>#include <asm/io.h> /* for virt_to_bus, etc. */#include "scsi.h"#include "hosts.h"#include "sd.h"#include "dpt/dptsig.h"#include "dpti.h"/*============================================================================ * Create a binary signature - this is read by dptsig * Needed for our management apps *============================================================================ */static dpt_sig_S DPTI_sig = { {'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION,#ifdef __i386__ PROC_INTEL, PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM,#elif defined(__ia64__) PROC_INTEL, PROC_IA64,#elif defined(__sparc__) PROC_ULTRASPARC,#elif defined(__alpha__) PROC_ALPHA ,#else (-1),#endif FT_HBADRVR, 0, OEM_DPT, OS_LINUX, CAP_OVERLAP, DEV_ALL, ADF_ALL_SC5, 0, 0, DPT_VERSION, DPT_REVISION, DPT_SUBREVISION, DPT_MONTH, DPT_DAY, DPT_YEAR, "Adaptec Linux I2O RAID Driver"};/*============================================================================ * Globals *============================================================================ */DECLARE_MUTEX(adpt_configuration_lock);static struct i2o_sys_tbl *sys_tbl = NULL;static int sys_tbl_ind = 0;static int sys_tbl_len = 0;static adpt_hba* hbas[DPTI_MAX_HBA];static adpt_hba* hba_chain = NULL;static int hba_count = 0;// Debug flags to be put into the HBA flags field when initialized// Make sure to enable DEBUG_PRINT for these flags to workstatic unsigned long DebugFlags = HBA_FLAGS_DBG_SCAN_B | HBA_FLAGS_DBG_FLAGS_MASK;static struct file_operations adpt_fops = { ioctl: adpt_ioctl, open: adpt_open, release: adpt_close};#ifdef REBOOT_NOTIFIERstatic struct notifier_block adpt_reboot_notifier ={ adpt_reboot_event, NULL, 0};#endif/* Structures and definitions for synchronous message posting. * See adpt_i2o_post_wait() for description * */struct adpt_i2o_post_wait_data{ int status; u32 id; adpt_wait_queue_head_t *wq; struct adpt_i2o_post_wait_data *next;};static struct adpt_i2o_post_wait_data *adpt_post_wait_queue = NULL;static u32 adpt_post_wait_id = 0;static spinlock_t adpt_post_wait_lock = SPIN_LOCK_UNLOCKED;/*============================================================================ * Functions *============================================================================ */static u8 adpt_read_blink_led(adpt_hba* host){ if(host->FwDebugBLEDflag_P != 0) { if( readb(host->FwDebugBLEDflag_P) == 0xbc ){ return readb(host->FwDebugBLEDvalue_P); } } return 0;}/*============================================================================ * Scsi host template interface functions *============================================================================ */static struct pci_device_id dptids[] = { { PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, { PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, { 0, }};MODULE_DEVICE_TABLE(pci,dptids);static int adpt_detect(Scsi_Host_Template* sht){ struct pci_dev *pDev = NULL; adpt_hba* pHba; adpt_init(); sht->use_new_eh_code = 1; PINFO("Detecting Adaptec I2O RAID controllers...\n"); /* search for all Adatpec I2O RAID cards */ while ((pDev = pci_find_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) { if(pDev->device == PCI_DPT_DEVICE_ID || pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){ if(adpt_install_hba(sht, pDev) ){ PERROR("Could not Init an I2O RAID device\n"); PERROR("Will not try to detect others.\n"); return hba_count-1; } } } /* In INIT state, Activate IOPs */ for (pHba = hba_chain; pHba; pHba = pHba->next) { // Activate does get status , init outbound, and get hrt if (adpt_i2o_activate_hba(pHba) < 0) { adpt_i2o_delete_hba(pHba); } } /* Active IOPs in HOLD state */rebuild_sys_tab: if (hba_chain == NULL) return 0; /* * If build_sys_table fails, we kill everything and bail * as we can't init the IOPs w/o a system table */ if (adpt_i2o_build_sys_table() < 0) { adpt_i2o_sys_shutdown(); return 0; } PDEBUG("HBA's in HOLD state\n"); /* If IOP don't get online, we need to rebuild the System table */ for (pHba = hba_chain; pHba; pHba = pHba->next) { if (adpt_i2o_online_hba(pHba) < 0) { adpt_i2o_delete_hba(pHba); goto rebuild_sys_tab; } } /* Active IOPs now in OPERATIONAL state */ PDEBUG("HBA's in OPERATIONAL state\n"); printk(KERN_INFO"dpti: If you have a lot of devices this could take a few minutes.\n"); for (pHba = hba_chain; pHba; pHba = pHba->next) { printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name); if (adpt_i2o_lct_get(pHba) < 0){ adpt_i2o_delete_hba(pHba); continue; } if (adpt_i2o_parse_lct(pHba) < 0){ adpt_i2o_delete_hba(pHba); continue; } adpt_inquiry(pHba); } for (pHba = hba_chain; pHba; pHba = pHba->next) { if( adpt_scsi_register(pHba,sht) < 0){ adpt_i2o_delete_hba(pHba); continue; } pHba->initialized = TRUE; pHba->state &= ~DPTI_STATE_RESET; } // Register our control device node // nodes will need to be created in /dev to access this // the nodes can not be created from within the driver if (hba_count && register_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER, &adpt_fops)) { adpt_i2o_sys_shutdown(); return 0; } return hba_count;}/* * scsi_unregister will be called AFTER we return. */static int adpt_release(struct Scsi_Host *host){ adpt_hba* pHba = (adpt_hba*) host->hostdata[0];// adpt_i2o_quiesce_hba(pHba); adpt_i2o_delete_hba(pHba); return 0;}static void adpt_inquiry(adpt_hba* pHba){ u32 msg[14]; u32 *mptr; u32 *lenptr; int direction; int scsidir; u32 len; u32 reqlen; u8* buf; u8 scb[16]; s32 rcode; memset(msg, 0, sizeof(msg)); buf = (u8*)kmalloc(80,GFP_KERNEL|ADDR32); if(!buf){ printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name); return; } memset((void*)buf, 0, 36); len = 36; direction = 0x00000000; scsidir =0x40000000; // DATA IN (iop<--dev) reqlen = 14; // SINGLE SGE /* Stick the headers on */ msg[0] = reqlen<<16 | SGL_OFFSET_12; msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID); msg[2] = 0; msg[3] = 0; // Adaptec/DPT Private stuff msg[4] = I2O_CMD_SCSI_EXEC|DPT_ORGANIZATION_ID<<16; msg[5] = ADAPTER_TID | 1<<16 /* Interpret*/; /* Direction, disconnect ok | sense data | simple queue , CDBLen */ // I2O_SCB_FLAG_ENABLE_DISCONNECT | // I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | // I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE; msg[6] = scsidir|0x20a00000| 6 /* cmd len*/; mptr=msg+7; memset(scb, 0, sizeof(scb)); // Write SCSI command into the message - always 16 byte block scb[0] = INQUIRY; scb[1] = 0; scb[2] = 0; scb[3] = 0; scb[4] = 36; scb[5] = 0; // Don't care about the rest of scb memcpy(mptr, scb, sizeof(scb)); mptr+=4; lenptr=mptr++; /* Remember me - fill in when we know */ /* Now fill in the SGList and command */ *lenptr = len; *mptr++ = 0xD0000000|direction|len; *mptr++ = virt_to_bus(buf); // Send it on it's way rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120); if (rcode != 0) { sprintf(pHba->detail, "Adaptec I2O RAID"); printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode); } else { memset(pHba->detail, 0, sizeof(pHba->detail)); memcpy(&(pHba->detail), "Vendor: Adaptec ", 16); memcpy(&(pHba->detail[16]), " Model: ", 8); memcpy(&(pHba->detail[24]), (u8*) &buf[16], 16); memcpy(&(pHba->detail[40]), " FW: ", 4); memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4); pHba->detail[48] = '\0'; /* precautionary */ } kfree(buf); adpt_i2o_status_get(pHba); return ;}static void adpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device * devicelist){ Scsi_Device *device; /* scsi layer per device information */ adpt_hba* pHba; pHba = (adpt_hba *) host->hostdata[0]; for (device = devicelist; device != NULL; device = device->next) { if (device->host != host) { continue; } if (host->can_queue) { device->queue_depth = host->can_queue - 1; } else { device->queue_depth = 1; } }}static int adpt_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)){ adpt_hba* pHba = NULL; struct adpt_device* pDev = NULL; /* dpt per device information */ ulong timeout = jiffies + (TMOUT_SCSI*HZ); cmd->scsi_done = done; /* * SCSI REQUEST_SENSE commands will be executed automatically by the * Host Adapter for any errors, so they should not be executed * explicitly unless the Sense Data is zero indicating that no error * occurred. */ if ((cmd->cmnd[0] == REQUEST_SENSE) && (cmd->sense_buffer[0] != 0)) { cmd->result = (DID_OK << 16); cmd->scsi_done(cmd); return 0; } pHba = (adpt_hba*)cmd->host->hostdata[0]; if (!pHba) { return FAILED; } rmb(); /* * TODO: I need to block here if I am processing ioctl cmds * but if the outstanding cmds all finish before the ioctl, * the scsi-core will not know to start sending cmds to me again. * I need to a way to restart the scsi-cores queues or should I block * calling scsi_done on the outstanding cmds instead * for now we don't set the IOCTL state */ if(((pHba->state) & DPTI_STATE_IOCTL) || ((pHba->state) & DPTI_STATE_RESET)) { pHba->host->last_reset = jiffies; pHba->host->resetting = 1; return 1; } if(cmd->eh_state != SCSI_STATE_QUEUED){ // If we are not doing error recovery mod_timer(&cmd->eh_timeout, timeout); } // TODO if the cmd->device if offline then I may need to issue a bus rescan // followed by a get_lct to see if the device is there anymore if((pDev = (struct adpt_device*) (cmd->device->hostdata)) == NULL) { /* * First command request for this device. Set up a pointer * to the device structure. This should be a TEST_UNIT_READY * command from scan_scsis_single. */ if ((pDev = adpt_find_device(pHba, (u32)cmd->channel, (u32)cmd->target, (u32)cmd-> lun)) == NULL) { // TODO: if any luns are at this bus, scsi id then fake a TEST_UNIT_READY and INQUIRY response // with type 7F (for all luns less than the max for this bus,id) so the lun scan will continue. cmd->result = (DID_NO_CONNECT << 16); cmd->scsi_done(cmd); return 0; } (struct adpt_device*)(cmd->device->hostdata) = pDev; } pDev->pScsi_dev = cmd->device; /* * If we are being called from when the device is being reset, * delay processing of the command until later. */ if (pDev->state & DPTI_DEV_RESET ) { return FAILED; } return adpt_scsi_to_i2o(pHba, cmd, pDev);}static int adpt_bios_param(Disk* disk, kdev_t dev, int geom[]){ int heads=-1; int sectors=-1; int cylinders=-1; // *** First lets set the default geometry **** // If the capacity is less than ox2000 if (disk->capacity < 0x2000 ) { // floppy heads = 18; sectors = 2; } // else if between 0x2000 and 0x20000 else if (disk->capacity < 0x20000) { heads = 64; sectors = 32; } // else if between 0x20000 and 0x40000 else if (disk->capacity < 0x40000) { heads = 65; sectors = 63; } // else if between 0x4000 and 0x80000 else if (disk->capacity < 0x80000) { heads = 128; sectors = 63; } // else if greater than 0x80000 else { heads = 255; sectors = 63; } cylinders = disk->capacity / (heads * sectors); // Special case if CDROM if(disk->device->type == 5) { // CDROM heads = 252; sectors = 63; cylinders = 1111; } geom[0] = heads; geom[1] = sectors;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -