📄 fw-sbp2.c
字号:
/* * 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 + -