⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fw-sbp2.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * SBP2 driver (SCSI over IEEE1394) * * Copyright (C) 2005-2007  Kristian Hoegsberg <krh@bitplanet.net> * * 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. *//* * The basic structure of this driver is based on the old storage driver, * drivers/ieee1394/sbp2.c, originally written by *     James Goodwin <jamesg@filanet.com> * with later contributions and ongoing maintenance from *     Ben Collins <bcollins@debian.org>, *     Stefan Richter <stefanr@s5r6.in-berlin.de> * and many others. */#include <linux/kernel.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/mod_devicetable.h>#include <linux/device.h>#include <linux/scatterlist.h>#include <linux/dma-mapping.h>#include <linux/blkdev.h>#include <linux/string.h>#include <linux/stringify.h>#include <linux/timer.h>#include <linux/workqueue.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_device.h>#include <scsi/scsi_host.h>#include "fw-transaction.h"#include "fw-topology.h"#include "fw-device.h"/* * So far only bridges from Oxford Semiconductor are known to support * concurrent logins. Depending on firmware, four or two concurrent logins * are possible on OXFW911 and newer Oxsemi bridges. * * Concurrent logins are useful together with cluster filesystems. */static int sbp2_param_exclusive_login = 1;module_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644);MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device "		 "(default = Y, use N for concurrent initiators)");/* * Flags for firmware oddities * * - 128kB max transfer *   Limit transfer size. Necessary for some old bridges. * * - 36 byte inquiry *   When scsi_mod probes the device, let the inquiry command look like that *   from MS Windows. * * - skip mode page 8 *   Suppress sending of mode_sense for mode page 8 if the device pretends to *   support the SCSI Primary Block commands instead of Reduced Block Commands. * * - fix capacity *   Tell sd_mod to correct the last sector number reported by read_capacity. *   Avoids access beyond actual disk limits on devices with an off-by-one bug. *   Don't use this with devices which don't have this bug. * * - override internal blacklist *   Instead of adding to the built-in blacklist, use only the workarounds *   specified in the module load parameter. *   Useful if a blacklist entry interfered with a non-broken device. */#define SBP2_WORKAROUND_128K_MAX_TRANS	0x1#define SBP2_WORKAROUND_INQUIRY_36	0x2#define SBP2_WORKAROUND_MODE_SENSE_8	0x4#define SBP2_WORKAROUND_FIX_CAPACITY	0x8#define SBP2_WORKAROUND_OVERRIDE	0x100static int sbp2_param_workarounds;module_param_named(workarounds, sbp2_param_workarounds, int, 0644);MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"	", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS)	", 36 byte inquiry = "    __stringify(SBP2_WORKAROUND_INQUIRY_36)	", skip mode page 8 = "   __stringify(SBP2_WORKAROUND_MODE_SENSE_8)	", fix capacity = "       __stringify(SBP2_WORKAROUND_FIX_CAPACITY)	", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)	", or a combination)");/* I don't know why the SCSI stack doesn't define something like this... */typedef void (*scsi_done_fn_t)(struct scsi_cmnd *);static const char sbp2_driver_name[] = "sbp2";/* * We create one struct sbp2_logical_unit per SBP-2 Logical Unit Number Entry * and one struct scsi_device per sbp2_logical_unit. */struct sbp2_logical_unit {	struct sbp2_target *tgt;	struct list_head link;	struct scsi_device *sdev;	struct fw_address_handler address_handler;	struct list_head orb_list;	u64 command_block_agent_address;	u16 lun;	int login_id;	/*	 * The generation is updated once we've logged in or reconnected	 * to the logical unit.  Thus, I/O to the device will automatically	 * fail and get retried if it happens in a window where the device	 * is not ready, e.g. after a bus reset but before we reconnect.	 */	int generation;	int retries;	struct delayed_work work;};/* * We create one struct sbp2_target per IEEE 1212 Unit Directory * and one struct Scsi_Host per sbp2_target. */struct sbp2_target {	struct kref kref;	struct fw_unit *unit;	u64 management_agent_address;	int directory_id;	int node_id;	int address_high;	unsigned workarounds;	struct list_head lu_list;};#define SBP2_MAX_SG_ELEMENT_LENGTH	0xf000#define SBP2_MAX_SECTORS		255	/* Max sectors supported */#define SBP2_ORB_TIMEOUT		2000	/* Timeout in ms */#define SBP2_ORB_NULL			0x80000000#define SBP2_DIRECTION_TO_MEDIA		0x0#define SBP2_DIRECTION_FROM_MEDIA	0x1/* Unit directory keys */#define SBP2_CSR_FIRMWARE_REVISION	0x3c#define SBP2_CSR_LOGICAL_UNIT_NUMBER	0x14#define SBP2_CSR_LOGICAL_UNIT_DIRECTORY	0xd4/* Management orb opcodes */#define SBP2_LOGIN_REQUEST		0x0#define SBP2_QUERY_LOGINS_REQUEST	0x1#define SBP2_RECONNECT_REQUEST		0x3#define SBP2_SET_PASSWORD_REQUEST	0x4#define SBP2_LOGOUT_REQUEST		0x7#define SBP2_ABORT_TASK_REQUEST		0xb#define SBP2_ABORT_TASK_SET		0xc#define SBP2_LOGICAL_UNIT_RESET		0xe#define SBP2_TARGET_RESET_REQUEST	0xf/* Offsets for command block agent registers */#define SBP2_AGENT_STATE		0x00#define SBP2_AGENT_RESET		0x04#define SBP2_ORB_POINTER		0x08#define SBP2_DOORBELL			0x10#define SBP2_UNSOLICITED_STATUS_ENABLE	0x14/* Status write response codes */#define SBP2_STATUS_REQUEST_COMPLETE	0x0#define SBP2_STATUS_TRANSPORT_FAILURE	0x1#define SBP2_STATUS_ILLEGAL_REQUEST	0x2#define SBP2_STATUS_VENDOR_DEPENDENT	0x3#define STATUS_GET_ORB_HIGH(v)		((v).status & 0xffff)#define STATUS_GET_SBP_STATUS(v)	(((v).status >> 16) & 0xff)#define STATUS_GET_LEN(v)		(((v).status >> 24) & 0x07)#define STATUS_GET_DEAD(v)		(((v).status >> 27) & 0x01)#define STATUS_GET_RESPONSE(v)		(((v).status >> 28) & 0x03)#define STATUS_GET_SOURCE(v)		(((v).status >> 30) & 0x03)#define STATUS_GET_ORB_LOW(v)		((v).orb_low)#define STATUS_GET_DATA(v)		((v).data)struct sbp2_status {	u32 status;	u32 orb_low;	u8 data[24];};struct sbp2_pointer {	u32 high;	u32 low;};struct sbp2_orb {	struct fw_transaction t;	struct kref kref;	dma_addr_t request_bus;	int rcode;	struct sbp2_pointer pointer;	void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status);	struct list_head link;};#define MANAGEMENT_ORB_LUN(v)			((v))#define MANAGEMENT_ORB_FUNCTION(v)		((v) << 16)#define MANAGEMENT_ORB_RECONNECT(v)		((v) << 20)#define MANAGEMENT_ORB_EXCLUSIVE(v)		((v) ? 1 << 28 : 0)#define MANAGEMENT_ORB_REQUEST_FORMAT(v)	((v) << 29)#define MANAGEMENT_ORB_NOTIFY			((1) << 31)#define MANAGEMENT_ORB_RESPONSE_LENGTH(v)	((v))#define MANAGEMENT_ORB_PASSWORD_LENGTH(v)	((v) << 16)struct sbp2_management_orb {	struct sbp2_orb base;	struct {		struct sbp2_pointer password;		struct sbp2_pointer response;		u32 misc;		u32 length;		struct sbp2_pointer status_fifo;	} request;	__be32 response[4];	dma_addr_t response_bus;	struct completion done;	struct sbp2_status status;};#define LOGIN_RESPONSE_GET_LOGIN_ID(v)	((v).misc & 0xffff)#define LOGIN_RESPONSE_GET_LENGTH(v)	(((v).misc >> 16) & 0xffff)struct sbp2_login_response {	u32 misc;	struct sbp2_pointer command_block_agent;	u32 reconnect_hold;};#define COMMAND_ORB_DATA_SIZE(v)	((v))#define COMMAND_ORB_PAGE_SIZE(v)	((v) << 16)#define COMMAND_ORB_PAGE_TABLE_PRESENT	((1) << 19)#define COMMAND_ORB_MAX_PAYLOAD(v)	((v) << 20)#define COMMAND_ORB_SPEED(v)		((v) << 24)#define COMMAND_ORB_DIRECTION(v)	((v) << 27)#define COMMAND_ORB_REQUEST_FORMAT(v)	((v) << 29)#define COMMAND_ORB_NOTIFY		((1) << 31)struct sbp2_command_orb {	struct sbp2_orb base;	struct {		struct sbp2_pointer next;		struct sbp2_pointer data_descriptor;		u32 misc;		u8 command_block[12];	} request;	struct scsi_cmnd *cmd;	scsi_done_fn_t done;	struct sbp2_logical_unit *lu;	struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8)));	dma_addr_t page_table_bus;};/* * List of devices with known bugs. * * The firmware_revision field, masked with 0xffff00, is the best * indicator for the type of bridge chip of a device.  It yields a few * false positives but this did not break correctly behaving devices * so far.  We use ~0 as a wildcard, since the 24 bit values we get * from the config rom can never match that. */static const struct {	u32 firmware_revision;	u32 model;	unsigned workarounds;} sbp2_workarounds_table[] = {	/* DViCO Momobay CX-1 with TSB42AA9 bridge */ {		.firmware_revision	= 0x002800,		.model			= 0x001010,		.workarounds		= SBP2_WORKAROUND_INQUIRY_36 |					  SBP2_WORKAROUND_MODE_SENSE_8,	},	/* Initio bridges, actually only needed for some older ones */ {		.firmware_revision	= 0x000200,		.model			= ~0,		.workarounds		= SBP2_WORKAROUND_INQUIRY_36,	},	/* Symbios bridge */ {		.firmware_revision	= 0xa0b800,		.model			= ~0,		.workarounds		= SBP2_WORKAROUND_128K_MAX_TRANS,	},	/*	 * There are iPods (2nd gen, 3rd gen) with model_id == 0, but	 * these iPods do not feature the read_capacity bug according	 * to one report.  Read_capacity behaviour as well as model_id	 * could change due to Apple-supplied firmware updates though.	 */	/* iPod 4th generation. */ {		.firmware_revision	= 0x0a2700,		.model			= 0x000021,		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,	},	/* iPod mini */ {		.firmware_revision	= 0x0a2700,		.model			= 0x000023,		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,	},	/* iPod Photo */ {		.firmware_revision	= 0x0a2700,		.model			= 0x00007e,		.workarounds		= SBP2_WORKAROUND_FIX_CAPACITY,	}};static voidfree_orb(struct kref *kref){	struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref);	kfree(orb);}static voidsbp2_status_write(struct fw_card *card, struct fw_request *request,		  int tcode, int destination, int source,		  int generation, int speed,		  unsigned long long offset,		  void *payload, size_t length, void *callback_data){	struct sbp2_logical_unit *lu = callback_data;	struct sbp2_orb *orb;	struct sbp2_status status;	size_t header_size;	unsigned long flags;	if (tcode != TCODE_WRITE_BLOCK_REQUEST ||	    length == 0 || length > sizeof(status)) {		fw_send_response(card, request, RCODE_TYPE_ERROR);		return;	}	header_size = min(length, 2 * sizeof(u32));	fw_memcpy_from_be32(&status, payload, header_size);	if (length > header_size)		memcpy(status.data, payload + 8, length - header_size);	if (STATUS_GET_SOURCE(status) == 2 || STATUS_GET_SOURCE(status) == 3) {		fw_notify("non-orb related status write, not handled\n");		fw_send_response(card, request, RCODE_COMPLETE);		return;	}	/* Lookup the orb corresponding to this status write. */	spin_lock_irqsave(&card->lock, flags);	list_for_each_entry(orb, &lu->orb_list, link) {		if (STATUS_GET_ORB_HIGH(status) == 0 &&		    STATUS_GET_ORB_LOW(status) == orb->request_bus) {			orb->rcode = RCODE_COMPLETE;			list_del(&orb->link);			break;		}	}	spin_unlock_irqrestore(&card->lock, flags);	if (&orb->link != &lu->orb_list)		orb->callback(orb, &status);	else		fw_error("status write for unknown orb\n");	kref_put(&orb->kref, free_orb);	fw_send_response(card, request, RCODE_COMPLETE);}static voidcomplete_transaction(struct fw_card *card, int rcode,		     void *payload, size_t length, void *data){	struct sbp2_orb *orb = data;	unsigned long flags;	/*	 * This is a little tricky.  We can get the status write for	 * the orb before we get this callback.  The status write	 * handler above will assume the orb pointer transaction was	 * successful and set the rcode to RCODE_COMPLETE for the orb.	 * So this callback only sets the rcode if it hasn't already	 * been set and only does the cleanup if the transaction	 * failed and we didn't already get a status write.	 */	spin_lock_irqsave(&card->lock, flags);	if (orb->rcode == -1)		orb->rcode = rcode;	if (orb->rcode != RCODE_COMPLETE) {		list_del(&orb->link);		spin_unlock_irqrestore(&card->lock, flags);		orb->callback(orb, NULL);	} else {		spin_unlock_irqrestore(&card->lock, flags);	}	kref_put(&orb->kref, free_orb);}static voidsbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,	      int node_id, int generation, u64 offset){	struct fw_device *device = fw_device(lu->tgt->unit->device.parent);	unsigned long flags;	orb->pointer.high = 0;	orb->pointer.low = orb->request_bus;	fw_memcpy_to_be32(&orb->pointer, &orb->pointer, sizeof(orb->pointer));	spin_lock_irqsave(&device->card->lock, flags);	list_add_tail(&orb->link, &lu->orb_list);	spin_unlock_irqrestore(&device->card->lock, flags);	/* Take a ref for the orb list and for the transaction callback. */	kref_get(&orb->kref);	kref_get(&orb->kref);	fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST,			node_id, generation, device->max_speed, offset,			&orb->pointer, sizeof(orb->pointer),			complete_transaction, orb);}static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu){	struct fw_device *device = fw_device(lu->tgt->unit->device.parent);	struct sbp2_orb *orb, *next;	struct list_head list;	unsigned long flags;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -