📄 sbp2.c
字号:
/* * sbp2.c - SBP-2 protocol driver for IEEE-1394 * * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com) * jamesg@filanet.com (JSG) * * Copyright (C) 2003 Ben Collins <bcollins@debian.org> * * 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. * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *//* * Brief Description: * * This driver implements the Serial Bus Protocol 2 (SBP-2) over IEEE-1394 * under Linux. The SBP-2 driver is implemented as an IEEE-1394 high-level * driver. It also registers as a SCSI lower-level driver in order to accept * SCSI commands for transport using SBP-2. * * You may access any attached SBP-2 storage devices as if they were SCSI * devices (e.g. mount /dev/sda1, fdisk, mkfs, etc.). * * Current Issues: * * - Error Handling: SCSI aborts and bus reset requests are handled somewhat * but the code needs additional debugging. */#include <linux/config.h>#include <linux/kernel.h>#include <linux/list.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/fs.h>#include <linux/poll.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/sched.h>#include <linux/blkdev.h>#include <linux/smp_lock.h>#include <linux/init.h>#include <linux/pci.h>#include <asm/current.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/byteorder.h>#include <asm/atomic.h>#include <asm/system.h>#include <asm/scatterlist.h>#include "../scsi/scsi.h"#include <scsi/scsi_host.h>#include "csr1212.h"#include "ieee1394.h"#include "ieee1394_types.h"#include "ieee1394_core.h"#include "nodemgr.h"#include "hosts.h"#include "highlevel.h"#include "ieee1394_transactions.h"#include "sbp2.h"static char version[] __devinitdata = "$Rev: 1219 $ Ben Collins <bcollins@debian.org>";/* * Module load parameter definitions *//* * Change max_speed on module load if you have a bad IEEE-1394 * controller that has trouble running 2KB packets at 400mb. * * NOTE: On certain OHCI parts I have seen short packets on async transmit * (probably due to PCI latency/throughput issues with the part). You can * bump down the speed if you are running into problems. */static int max_speed = IEEE1394_SPEED_MAX;module_param(max_speed, int, 0644);MODULE_PARM_DESC(max_speed, "Force max speed (3 = 800mb, 2 = 400mb default, 1 = 200mb, 0 = 100mb)");/* * Set serialize_io to 1 if you'd like only one scsi command sent * down to us at a time (debugging). This might be necessary for very * badly behaved sbp2 devices. */static int serialize_io = 0;module_param(serialize_io, int, 0444);MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");/* * Bump up max_sectors if you'd like to support very large sized * transfers. Please note that some older sbp2 bridge chips are broken for * transfers greater or equal to 128KB. Default is a value of 255 * sectors, or just under 128KB (at 512 byte sector size). I can note that * the Oxsemi sbp2 chipsets have no problems supporting very large * transfer sizes. */static int max_sectors = SBP2_MAX_SECTORS;module_param(max_sectors, int, 0444);MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported (default = 255)");/* * Exclusive login to sbp2 device? In most cases, the sbp2 driver should * do an exclusive login, as it's generally unsafe to have two hosts * talking to a single sbp2 device at the same time (filesystem coherency, * etc.). If you're running an sbp2 device that supports multiple logins, * and you're either running read-only filesystems or some sort of special * filesystem supporting multiple hosts (one such filesystem is OpenGFS, * see opengfs.sourceforge.net for more info), then set exclusive_login * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four * concurrent logins. */static int exclusive_login = 1;module_param(exclusive_login, int, 0644);MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device (default = 1)");/* * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on * if your sbp2 device is not properly handling the SCSI inquiry command. * This hack makes the inquiry look more like a typical MS Windows * inquiry. * * If force_inquiry_hack=1 is required for your device to work, * please submit the logged sbp2_firmware_revision value of this device to * the linux1394-devel mailing list. */static int force_inquiry_hack = 0;module_param(force_inquiry_hack, int, 0444);MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");/* * Export information about protocols/devices supported by this driver. */static struct ieee1394_device_id sbp2_id_table[] = { { .match_flags =IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff, .version = SBP2_SW_VERSION_ENTRY & 0xffffff }, { }};MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table);/* * Debug levels, configured via kernel config, or enable here. *//* #define CONFIG_IEEE1394_SBP2_DEBUG_ORBS *//* #define CONFIG_IEEE1394_SBP2_DEBUG_DMA *//* #define CONFIG_IEEE1394_SBP2_DEBUG 1 *//* #define CONFIG_IEEE1394_SBP2_DEBUG 2 *//* #define CONFIG_IEEE1394_SBP2_PACKET_DUMP */#ifdef CONFIG_IEEE1394_SBP2_DEBUG_ORBS#define SBP2_ORB_DEBUG(fmt, args...) HPSB_ERR("sbp2(%s): "fmt, __FUNCTION__, ## args)static u32 global_outstanding_command_orbs = 0;#define outstanding_orb_incr global_outstanding_command_orbs++#define outstanding_orb_decr global_outstanding_command_orbs--#else#define SBP2_ORB_DEBUG(fmt, args...)#define outstanding_orb_incr#define outstanding_orb_decr#endif#ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA#define SBP2_DMA_ALLOC(fmt, args...) \ HPSB_ERR("sbp2(%s)alloc(%d): "fmt, __FUNCTION__, \ ++global_outstanding_dmas, ## args)#define SBP2_DMA_FREE(fmt, args...) \ HPSB_ERR("sbp2(%s)free(%d): "fmt, __FUNCTION__, \ --global_outstanding_dmas, ## args)static u32 global_outstanding_dmas = 0;#else#define SBP2_DMA_ALLOC(fmt, args...)#define SBP2_DMA_FREE(fmt, args...)#endif#if CONFIG_IEEE1394_SBP2_DEBUG >= 2#define SBP2_DEBUG(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)#define SBP2_INFO(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)#define SBP2_NOTICE(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)#define SBP2_WARN(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)#elif CONFIG_IEEE1394_SBP2_DEBUG == 1#define SBP2_DEBUG(fmt, args...) HPSB_DEBUG("sbp2: "fmt, ## args)#define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args)#define SBP2_NOTICE(fmt, args...) HPSB_NOTICE("sbp2: "fmt, ## args)#define SBP2_WARN(fmt, args...) HPSB_WARN("sbp2: "fmt, ## args)#else#define SBP2_DEBUG(fmt, args...)#define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args)#define SBP2_NOTICE(fmt, args...) HPSB_NOTICE("sbp2: "fmt, ## args)#define SBP2_WARN(fmt, args...) HPSB_WARN("sbp2: "fmt, ## args)#endif#define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)/* * Globals */static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id, u32 status);static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id, u32 scsi_status, Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));static Scsi_Host_Template scsi_driver_template;const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC };static void sbp2_host_reset(struct hpsb_host *host);static int sbp2_probe(struct device *dev);static int sbp2_remove(struct device *dev);static int sbp2_update(struct unit_directory *ud);static struct hpsb_highlevel sbp2_highlevel = { .name = SBP2_DEVICE_NAME, .host_reset = sbp2_host_reset,};static struct hpsb_address_ops sbp2_ops = { .write = sbp2_handle_status_write};#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMAstatic struct hpsb_address_ops sbp2_physdma_ops = { .read = sbp2_handle_physdma_read, .write = sbp2_handle_physdma_write,};#endifstatic struct hpsb_protocol_driver sbp2_driver = { .name = "SBP2 Driver", .id_table = sbp2_id_table, .update = sbp2_update, .driver = { .name = SBP2_DEVICE_NAME, .bus = &ieee1394_bus_type, .probe = sbp2_probe, .remove = sbp2_remove, },};/* List of device firmware's that require a forced 36 byte inquiry. */static u32 sbp2_broken_inquiry_list[] = { 0x00002800, /* Stefan Richter <richtest@bauwesen.tu-cottbus.de> */ /* DViCO Momobay CX-1 */ 0x00000200 /* Andreas Plesch <plesch@fas.harvard.edu> */ /* QPS Fire DVDBurner */};#define NUM_BROKEN_INQUIRY_DEVS \ (sizeof(sbp2_broken_inquiry_list)/sizeof(*sbp2_broken_inquiry_list))/************************************** * General utility functions **************************************/#ifndef __BIG_ENDIAN/* * Converts a buffer from be32 to cpu byte ordering. Length is in bytes. */static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length){ u32 *temp = buffer; for (length = (length >> 2); length--; ) temp[length] = be32_to_cpu(temp[length]); return;}/* * Converts a buffer from cpu to be32 byte ordering. Length is in bytes. */static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length){ u32 *temp = buffer; for (length = (length >> 2); length--; ) temp[length] = cpu_to_be32(temp[length]); return;}#else /* BIG_ENDIAN *//* Why waste the cpu cycles? */#define sbp2util_be32_to_cpu_buffer(x,y)#define sbp2util_cpu_to_be32_buffer(x,y)#endif#ifdef CONFIG_IEEE1394_SBP2_PACKET_DUMP/* * Debug packet dump routine. Length is in bytes. */static void sbp2util_packet_dump(void *buffer, int length, char *dump_name, u32 dump_phys_addr){ int i; unsigned char *dump = buffer; if (!dump || !length || !dump_name) return; if (dump_phys_addr) printk("[%s, 0x%x]", dump_name, dump_phys_addr); else printk("[%s]", dump_name); for (i = 0; i < length; i++) { if (i > 0x3f) { printk("\n ..."); break; } if ((i & 0x3) == 0) printk(" "); if ((i & 0xf) == 0) printk("\n "); printk("%02x ", (int) dump[i]); } printk("\n"); return;}#else#define sbp2util_packet_dump(w,x,y,z)#endif/* * Goofy routine that basically does a down_timeout function. */static int sbp2util_down_timeout(atomic_t *done, int timeout){ int i; for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) { set_current_state(TASK_INTERRUPTIBLE); if (schedule_timeout(HZ/10)) /* 100ms */ return(1); } return ((i > 0) ? 0:1);}/* Free's an allocated packet */static void sbp2_free_packet(struct hpsb_packet *packet){ hpsb_free_tlabel(packet); hpsb_free_packet(packet);}/* This is much like hpsb_node_write(), except it ignores the response * subaction and returns immediately. Can be used from interrupts. */int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr, quadlet_t *buffer, size_t length){ struct hpsb_packet *packet; packet = hpsb_make_writepacket(ne->host, ne->nodeid, addr, buffer, length); if (!packet) return -ENOMEM; hpsb_set_packet_complete_task(packet, (void (*)(void*))sbp2_free_packet, packet); hpsb_node_fill_packet(ne, packet); if (hpsb_send_packet(packet) < 0) { sbp2_free_packet(packet); return -EIO; } return 0;}/* * This function is called to create a pool of command orbs used for * command processing. It is called when a new sbp2 device is detected. */static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id){ struct sbp2scsi_host_info *hi = scsi_id->hi; int i; unsigned long flags, orbs; struct sbp2_command_info *command; orbs = serialize_io ? 2 : SBP2_MAX_CMDS; spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); for (i = 0; i < orbs; i++) { command = (struct sbp2_command_info *) kmalloc(sizeof(struct sbp2_command_info), GFP_ATOMIC); if (!command) { spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); return(-ENOMEM); } memset(command, '\0', sizeof(struct sbp2_command_info)); command->command_orb_dma = pci_map_single (hi->host->pdev, &command->command_orb, sizeof(struct sbp2_command_orb), PCI_DMA_BIDIRECTIONAL); SBP2_DMA_ALLOC("single command orb DMA"); command->sge_dma = pci_map_single (hi->host->pdev, &command->scatter_gather_element, sizeof(command->scatter_gather_element), PCI_DMA_BIDIRECTIONAL); SBP2_DMA_ALLOC("scatter_gather_element"); INIT_LIST_HEAD(&command->list); list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -