18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SBP2 driver (SCSI over IEEE1394) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2007 Kristian Hoegsberg <krh@bitplanet.net> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * The basic structure of this driver is based on the old storage driver, 108c2ecf20Sopenharmony_ci * drivers/ieee1394/sbp2.c, originally written by 118c2ecf20Sopenharmony_ci * James Goodwin <jamesg@filanet.com> 128c2ecf20Sopenharmony_ci * with later contributions and ongoing maintenance from 138c2ecf20Sopenharmony_ci * Ben Collins <bcollins@debian.org>, 148c2ecf20Sopenharmony_ci * Stefan Richter <stefanr@s5r6.in-berlin.de> 158c2ecf20Sopenharmony_ci * and many others. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 198c2ecf20Sopenharmony_ci#include <linux/bug.h> 208c2ecf20Sopenharmony_ci#include <linux/completion.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/device.h> 238c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 248c2ecf20Sopenharmony_ci#include <linux/firewire.h> 258c2ecf20Sopenharmony_ci#include <linux/firewire-constants.h> 268c2ecf20Sopenharmony_ci#include <linux/init.h> 278c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 288c2ecf20Sopenharmony_ci#include <linux/kernel.h> 298c2ecf20Sopenharmony_ci#include <linux/kref.h> 308c2ecf20Sopenharmony_ci#include <linux/list.h> 318c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 328c2ecf20Sopenharmony_ci#include <linux/module.h> 338c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 348c2ecf20Sopenharmony_ci#include <linux/scatterlist.h> 358c2ecf20Sopenharmony_ci#include <linux/slab.h> 368c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 378c2ecf20Sopenharmony_ci#include <linux/string.h> 388c2ecf20Sopenharmony_ci#include <linux/stringify.h> 398c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include <asm/byteorder.h> 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci#include <scsi/scsi.h> 448c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 458c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 468c2ecf20Sopenharmony_ci#include <scsi/scsi_host.h> 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * So far only bridges from Oxford Semiconductor are known to support 508c2ecf20Sopenharmony_ci * concurrent logins. Depending on firmware, four or two concurrent logins 518c2ecf20Sopenharmony_ci * are possible on OXFW911 and newer Oxsemi bridges. 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * Concurrent logins are useful together with cluster filesystems. 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic bool sbp2_param_exclusive_login = 1; 568c2ecf20Sopenharmony_cimodule_param_named(exclusive_login, sbp2_param_exclusive_login, bool, 0644); 578c2ecf20Sopenharmony_ciMODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device " 588c2ecf20Sopenharmony_ci "(default = Y, use N for concurrent initiators)"); 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * Flags for firmware oddities 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * - 128kB max transfer 648c2ecf20Sopenharmony_ci * Limit transfer size. Necessary for some old bridges. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * - 36 byte inquiry 678c2ecf20Sopenharmony_ci * When scsi_mod probes the device, let the inquiry command look like that 688c2ecf20Sopenharmony_ci * from MS Windows. 698c2ecf20Sopenharmony_ci * 708c2ecf20Sopenharmony_ci * - skip mode page 8 718c2ecf20Sopenharmony_ci * Suppress sending of mode_sense for mode page 8 if the device pretends to 728c2ecf20Sopenharmony_ci * support the SCSI Primary Block commands instead of Reduced Block Commands. 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * - fix capacity 758c2ecf20Sopenharmony_ci * Tell sd_mod to correct the last sector number reported by read_capacity. 768c2ecf20Sopenharmony_ci * Avoids access beyond actual disk limits on devices with an off-by-one bug. 778c2ecf20Sopenharmony_ci * Don't use this with devices which don't have this bug. 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * - delay inquiry 808c2ecf20Sopenharmony_ci * Wait extra SBP2_INQUIRY_DELAY seconds after login before SCSI inquiry. 818c2ecf20Sopenharmony_ci * 828c2ecf20Sopenharmony_ci * - power condition 838c2ecf20Sopenharmony_ci * Set the power condition field in the START STOP UNIT commands sent by 848c2ecf20Sopenharmony_ci * sd_mod on suspend, resume, and shutdown (if manage_start_stop is on). 858c2ecf20Sopenharmony_ci * Some disks need this to spin down or to resume properly. 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * - override internal blacklist 888c2ecf20Sopenharmony_ci * Instead of adding to the built-in blacklist, use only the workarounds 898c2ecf20Sopenharmony_ci * specified in the module load parameter. 908c2ecf20Sopenharmony_ci * Useful if a blacklist entry interfered with a non-broken device. 918c2ecf20Sopenharmony_ci */ 928c2ecf20Sopenharmony_ci#define SBP2_WORKAROUND_128K_MAX_TRANS 0x1 938c2ecf20Sopenharmony_ci#define SBP2_WORKAROUND_INQUIRY_36 0x2 948c2ecf20Sopenharmony_ci#define SBP2_WORKAROUND_MODE_SENSE_8 0x4 958c2ecf20Sopenharmony_ci#define SBP2_WORKAROUND_FIX_CAPACITY 0x8 968c2ecf20Sopenharmony_ci#define SBP2_WORKAROUND_DELAY_INQUIRY 0x10 978c2ecf20Sopenharmony_ci#define SBP2_INQUIRY_DELAY 12 988c2ecf20Sopenharmony_ci#define SBP2_WORKAROUND_POWER_CONDITION 0x20 998c2ecf20Sopenharmony_ci#define SBP2_WORKAROUND_OVERRIDE 0x100 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_cistatic int sbp2_param_workarounds; 1028c2ecf20Sopenharmony_cimodule_param_named(workarounds, sbp2_param_workarounds, int, 0644); 1038c2ecf20Sopenharmony_ciMODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0" 1048c2ecf20Sopenharmony_ci ", 128kB max transfer = " __stringify(SBP2_WORKAROUND_128K_MAX_TRANS) 1058c2ecf20Sopenharmony_ci ", 36 byte inquiry = " __stringify(SBP2_WORKAROUND_INQUIRY_36) 1068c2ecf20Sopenharmony_ci ", skip mode page 8 = " __stringify(SBP2_WORKAROUND_MODE_SENSE_8) 1078c2ecf20Sopenharmony_ci ", fix capacity = " __stringify(SBP2_WORKAROUND_FIX_CAPACITY) 1088c2ecf20Sopenharmony_ci ", delay inquiry = " __stringify(SBP2_WORKAROUND_DELAY_INQUIRY) 1098c2ecf20Sopenharmony_ci ", set power condition in start stop unit = " 1108c2ecf20Sopenharmony_ci __stringify(SBP2_WORKAROUND_POWER_CONDITION) 1118c2ecf20Sopenharmony_ci ", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE) 1128c2ecf20Sopenharmony_ci ", or a combination)"); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* 1158c2ecf20Sopenharmony_ci * We create one struct sbp2_logical_unit per SBP-2 Logical Unit Number Entry 1168c2ecf20Sopenharmony_ci * and one struct scsi_device per sbp2_logical_unit. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistruct sbp2_logical_unit { 1198c2ecf20Sopenharmony_ci struct sbp2_target *tgt; 1208c2ecf20Sopenharmony_ci struct list_head link; 1218c2ecf20Sopenharmony_ci struct fw_address_handler address_handler; 1228c2ecf20Sopenharmony_ci struct list_head orb_list; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci u64 command_block_agent_address; 1258c2ecf20Sopenharmony_ci u16 lun; 1268c2ecf20Sopenharmony_ci int login_id; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci /* 1298c2ecf20Sopenharmony_ci * The generation is updated once we've logged in or reconnected 1308c2ecf20Sopenharmony_ci * to the logical unit. Thus, I/O to the device will automatically 1318c2ecf20Sopenharmony_ci * fail and get retried if it happens in a window where the device 1328c2ecf20Sopenharmony_ci * is not ready, e.g. after a bus reset but before we reconnect. 1338c2ecf20Sopenharmony_ci */ 1348c2ecf20Sopenharmony_ci int generation; 1358c2ecf20Sopenharmony_ci int retries; 1368c2ecf20Sopenharmony_ci work_func_t workfn; 1378c2ecf20Sopenharmony_ci struct delayed_work work; 1388c2ecf20Sopenharmony_ci bool has_sdev; 1398c2ecf20Sopenharmony_ci bool blocked; 1408c2ecf20Sopenharmony_ci}; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci queue_delayed_work(fw_workqueue, &lu->work, delay); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci/* 1488c2ecf20Sopenharmony_ci * We create one struct sbp2_target per IEEE 1212 Unit Directory 1498c2ecf20Sopenharmony_ci * and one struct Scsi_Host per sbp2_target. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_cistruct sbp2_target { 1528c2ecf20Sopenharmony_ci struct fw_unit *unit; 1538c2ecf20Sopenharmony_ci struct list_head lu_list; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci u64 management_agent_address; 1568c2ecf20Sopenharmony_ci u64 guid; 1578c2ecf20Sopenharmony_ci int directory_id; 1588c2ecf20Sopenharmony_ci int node_id; 1598c2ecf20Sopenharmony_ci int address_high; 1608c2ecf20Sopenharmony_ci unsigned int workarounds; 1618c2ecf20Sopenharmony_ci unsigned int mgt_orb_timeout; 1628c2ecf20Sopenharmony_ci unsigned int max_payload; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci spinlock_t lock; 1658c2ecf20Sopenharmony_ci int dont_block; /* counter for each logical unit */ 1668c2ecf20Sopenharmony_ci int blocked; /* ditto */ 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic struct fw_device *target_parent_device(struct sbp2_target *tgt) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci return fw_parent_device(tgt->unit); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic const struct device *tgt_dev(const struct sbp2_target *tgt) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci return &tgt->unit->device; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic const struct device *lu_dev(const struct sbp2_logical_unit *lu) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci return &lu->tgt->unit->device; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci/* Impossible login_id, to detect logout attempt before successful login */ 1858c2ecf20Sopenharmony_ci#define INVALID_LOGIN_ID 0x10000 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci#define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */ 1888c2ecf20Sopenharmony_ci#define SBP2_ORB_NULL 0x80000000 1898c2ecf20Sopenharmony_ci#define SBP2_RETRY_LIMIT 0xf /* 15 retries */ 1908c2ecf20Sopenharmony_ci#define SBP2_CYCLE_LIMIT (0xc8 << 12) /* 200 125us cycles */ 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * There is no transport protocol limit to the CDB length, but we implement 1948c2ecf20Sopenharmony_ci * a fixed length only. 16 bytes is enough for disks larger than 2 TB. 1958c2ecf20Sopenharmony_ci */ 1968c2ecf20Sopenharmony_ci#define SBP2_MAX_CDB_SIZE 16 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci/* 1998c2ecf20Sopenharmony_ci * The maximum SBP-2 data buffer size is 0xffff. We quadlet-align this 2008c2ecf20Sopenharmony_ci * for compatibility with earlier versions of this driver. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci#define SBP2_MAX_SEG_SIZE 0xfffc 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci/* Unit directory keys */ 2058c2ecf20Sopenharmony_ci#define SBP2_CSR_UNIT_CHARACTERISTICS 0x3a 2068c2ecf20Sopenharmony_ci#define SBP2_CSR_FIRMWARE_REVISION 0x3c 2078c2ecf20Sopenharmony_ci#define SBP2_CSR_LOGICAL_UNIT_NUMBER 0x14 2088c2ecf20Sopenharmony_ci#define SBP2_CSR_UNIT_UNIQUE_ID 0x8d 2098c2ecf20Sopenharmony_ci#define SBP2_CSR_LOGICAL_UNIT_DIRECTORY 0xd4 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci/* Management orb opcodes */ 2128c2ecf20Sopenharmony_ci#define SBP2_LOGIN_REQUEST 0x0 2138c2ecf20Sopenharmony_ci#define SBP2_QUERY_LOGINS_REQUEST 0x1 2148c2ecf20Sopenharmony_ci#define SBP2_RECONNECT_REQUEST 0x3 2158c2ecf20Sopenharmony_ci#define SBP2_SET_PASSWORD_REQUEST 0x4 2168c2ecf20Sopenharmony_ci#define SBP2_LOGOUT_REQUEST 0x7 2178c2ecf20Sopenharmony_ci#define SBP2_ABORT_TASK_REQUEST 0xb 2188c2ecf20Sopenharmony_ci#define SBP2_ABORT_TASK_SET 0xc 2198c2ecf20Sopenharmony_ci#define SBP2_LOGICAL_UNIT_RESET 0xe 2208c2ecf20Sopenharmony_ci#define SBP2_TARGET_RESET_REQUEST 0xf 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci/* Offsets for command block agent registers */ 2238c2ecf20Sopenharmony_ci#define SBP2_AGENT_STATE 0x00 2248c2ecf20Sopenharmony_ci#define SBP2_AGENT_RESET 0x04 2258c2ecf20Sopenharmony_ci#define SBP2_ORB_POINTER 0x08 2268c2ecf20Sopenharmony_ci#define SBP2_DOORBELL 0x10 2278c2ecf20Sopenharmony_ci#define SBP2_UNSOLICITED_STATUS_ENABLE 0x14 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci/* Status write response codes */ 2308c2ecf20Sopenharmony_ci#define SBP2_STATUS_REQUEST_COMPLETE 0x0 2318c2ecf20Sopenharmony_ci#define SBP2_STATUS_TRANSPORT_FAILURE 0x1 2328c2ecf20Sopenharmony_ci#define SBP2_STATUS_ILLEGAL_REQUEST 0x2 2338c2ecf20Sopenharmony_ci#define SBP2_STATUS_VENDOR_DEPENDENT 0x3 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci#define STATUS_GET_ORB_HIGH(v) ((v).status & 0xffff) 2368c2ecf20Sopenharmony_ci#define STATUS_GET_SBP_STATUS(v) (((v).status >> 16) & 0xff) 2378c2ecf20Sopenharmony_ci#define STATUS_GET_LEN(v) (((v).status >> 24) & 0x07) 2388c2ecf20Sopenharmony_ci#define STATUS_GET_DEAD(v) (((v).status >> 27) & 0x01) 2398c2ecf20Sopenharmony_ci#define STATUS_GET_RESPONSE(v) (((v).status >> 28) & 0x03) 2408c2ecf20Sopenharmony_ci#define STATUS_GET_SOURCE(v) (((v).status >> 30) & 0x03) 2418c2ecf20Sopenharmony_ci#define STATUS_GET_ORB_LOW(v) ((v).orb_low) 2428c2ecf20Sopenharmony_ci#define STATUS_GET_DATA(v) ((v).data) 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_cistruct sbp2_status { 2458c2ecf20Sopenharmony_ci u32 status; 2468c2ecf20Sopenharmony_ci u32 orb_low; 2478c2ecf20Sopenharmony_ci u8 data[24]; 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistruct sbp2_pointer { 2518c2ecf20Sopenharmony_ci __be32 high; 2528c2ecf20Sopenharmony_ci __be32 low; 2538c2ecf20Sopenharmony_ci}; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistruct sbp2_orb { 2568c2ecf20Sopenharmony_ci struct fw_transaction t; 2578c2ecf20Sopenharmony_ci struct kref kref; 2588c2ecf20Sopenharmony_ci dma_addr_t request_bus; 2598c2ecf20Sopenharmony_ci int rcode; 2608c2ecf20Sopenharmony_ci void (*callback)(struct sbp2_orb * orb, struct sbp2_status * status); 2618c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu; 2628c2ecf20Sopenharmony_ci struct list_head link; 2638c2ecf20Sopenharmony_ci}; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci#define MANAGEMENT_ORB_LUN(v) ((v)) 2668c2ecf20Sopenharmony_ci#define MANAGEMENT_ORB_FUNCTION(v) ((v) << 16) 2678c2ecf20Sopenharmony_ci#define MANAGEMENT_ORB_RECONNECT(v) ((v) << 20) 2688c2ecf20Sopenharmony_ci#define MANAGEMENT_ORB_EXCLUSIVE(v) ((v) ? 1 << 28 : 0) 2698c2ecf20Sopenharmony_ci#define MANAGEMENT_ORB_REQUEST_FORMAT(v) ((v) << 29) 2708c2ecf20Sopenharmony_ci#define MANAGEMENT_ORB_NOTIFY ((1) << 31) 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci#define MANAGEMENT_ORB_RESPONSE_LENGTH(v) ((v)) 2738c2ecf20Sopenharmony_ci#define MANAGEMENT_ORB_PASSWORD_LENGTH(v) ((v) << 16) 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistruct sbp2_management_orb { 2768c2ecf20Sopenharmony_ci struct sbp2_orb base; 2778c2ecf20Sopenharmony_ci struct { 2788c2ecf20Sopenharmony_ci struct sbp2_pointer password; 2798c2ecf20Sopenharmony_ci struct sbp2_pointer response; 2808c2ecf20Sopenharmony_ci __be32 misc; 2818c2ecf20Sopenharmony_ci __be32 length; 2828c2ecf20Sopenharmony_ci struct sbp2_pointer status_fifo; 2838c2ecf20Sopenharmony_ci } request; 2848c2ecf20Sopenharmony_ci __be32 response[4]; 2858c2ecf20Sopenharmony_ci dma_addr_t response_bus; 2868c2ecf20Sopenharmony_ci struct completion done; 2878c2ecf20Sopenharmony_ci struct sbp2_status status; 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistruct sbp2_login_response { 2918c2ecf20Sopenharmony_ci __be32 misc; 2928c2ecf20Sopenharmony_ci struct sbp2_pointer command_block_agent; 2938c2ecf20Sopenharmony_ci __be32 reconnect_hold; 2948c2ecf20Sopenharmony_ci}; 2958c2ecf20Sopenharmony_ci#define COMMAND_ORB_DATA_SIZE(v) ((v)) 2968c2ecf20Sopenharmony_ci#define COMMAND_ORB_PAGE_SIZE(v) ((v) << 16) 2978c2ecf20Sopenharmony_ci#define COMMAND_ORB_PAGE_TABLE_PRESENT ((1) << 19) 2988c2ecf20Sopenharmony_ci#define COMMAND_ORB_MAX_PAYLOAD(v) ((v) << 20) 2998c2ecf20Sopenharmony_ci#define COMMAND_ORB_SPEED(v) ((v) << 24) 3008c2ecf20Sopenharmony_ci#define COMMAND_ORB_DIRECTION ((1) << 27) 3018c2ecf20Sopenharmony_ci#define COMMAND_ORB_REQUEST_FORMAT(v) ((v) << 29) 3028c2ecf20Sopenharmony_ci#define COMMAND_ORB_NOTIFY ((1) << 31) 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistruct sbp2_command_orb { 3058c2ecf20Sopenharmony_ci struct sbp2_orb base; 3068c2ecf20Sopenharmony_ci struct { 3078c2ecf20Sopenharmony_ci struct sbp2_pointer next; 3088c2ecf20Sopenharmony_ci struct sbp2_pointer data_descriptor; 3098c2ecf20Sopenharmony_ci __be32 misc; 3108c2ecf20Sopenharmony_ci u8 command_block[SBP2_MAX_CDB_SIZE]; 3118c2ecf20Sopenharmony_ci } request; 3128c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci struct sbp2_pointer page_table[SG_ALL] __attribute__((aligned(8))); 3158c2ecf20Sopenharmony_ci dma_addr_t page_table_bus; 3168c2ecf20Sopenharmony_ci}; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci#define SBP2_ROM_VALUE_WILDCARD ~0 /* match all */ 3198c2ecf20Sopenharmony_ci#define SBP2_ROM_VALUE_MISSING 0xff000000 /* not present in the unit dir. */ 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/* 3228c2ecf20Sopenharmony_ci * List of devices with known bugs. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * The firmware_revision field, masked with 0xffff00, is the best 3258c2ecf20Sopenharmony_ci * indicator for the type of bridge chip of a device. It yields a few 3268c2ecf20Sopenharmony_ci * false positives but this did not break correctly behaving devices 3278c2ecf20Sopenharmony_ci * so far. 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_cistatic const struct { 3308c2ecf20Sopenharmony_ci u32 firmware_revision; 3318c2ecf20Sopenharmony_ci u32 model; 3328c2ecf20Sopenharmony_ci unsigned int workarounds; 3338c2ecf20Sopenharmony_ci} sbp2_workarounds_table[] = { 3348c2ecf20Sopenharmony_ci /* DViCO Momobay CX-1 with TSB42AA9 bridge */ { 3358c2ecf20Sopenharmony_ci .firmware_revision = 0x002800, 3368c2ecf20Sopenharmony_ci .model = 0x001010, 3378c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_INQUIRY_36 | 3388c2ecf20Sopenharmony_ci SBP2_WORKAROUND_MODE_SENSE_8 | 3398c2ecf20Sopenharmony_ci SBP2_WORKAROUND_POWER_CONDITION, 3408c2ecf20Sopenharmony_ci }, 3418c2ecf20Sopenharmony_ci /* DViCO Momobay FX-3A with TSB42AA9A bridge */ { 3428c2ecf20Sopenharmony_ci .firmware_revision = 0x002800, 3438c2ecf20Sopenharmony_ci .model = 0x000000, 3448c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_POWER_CONDITION, 3458c2ecf20Sopenharmony_ci }, 3468c2ecf20Sopenharmony_ci /* Initio bridges, actually only needed for some older ones */ { 3478c2ecf20Sopenharmony_ci .firmware_revision = 0x000200, 3488c2ecf20Sopenharmony_ci .model = SBP2_ROM_VALUE_WILDCARD, 3498c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_INQUIRY_36, 3508c2ecf20Sopenharmony_ci }, 3518c2ecf20Sopenharmony_ci /* PL-3507 bridge with Prolific firmware */ { 3528c2ecf20Sopenharmony_ci .firmware_revision = 0x012800, 3538c2ecf20Sopenharmony_ci .model = SBP2_ROM_VALUE_WILDCARD, 3548c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_POWER_CONDITION, 3558c2ecf20Sopenharmony_ci }, 3568c2ecf20Sopenharmony_ci /* Symbios bridge */ { 3578c2ecf20Sopenharmony_ci .firmware_revision = 0xa0b800, 3588c2ecf20Sopenharmony_ci .model = SBP2_ROM_VALUE_WILDCARD, 3598c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, 3608c2ecf20Sopenharmony_ci }, 3618c2ecf20Sopenharmony_ci /* Datafab MD2-FW2 with Symbios/LSILogic SYM13FW500 bridge */ { 3628c2ecf20Sopenharmony_ci .firmware_revision = 0x002600, 3638c2ecf20Sopenharmony_ci .model = SBP2_ROM_VALUE_WILDCARD, 3648c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS, 3658c2ecf20Sopenharmony_ci }, 3668c2ecf20Sopenharmony_ci /* 3678c2ecf20Sopenharmony_ci * iPod 2nd generation: needs 128k max transfer size workaround 3688c2ecf20Sopenharmony_ci * iPod 3rd generation: needs fix capacity workaround 3698c2ecf20Sopenharmony_ci */ 3708c2ecf20Sopenharmony_ci { 3718c2ecf20Sopenharmony_ci .firmware_revision = 0x0a2700, 3728c2ecf20Sopenharmony_ci .model = 0x000000, 3738c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_128K_MAX_TRANS | 3748c2ecf20Sopenharmony_ci SBP2_WORKAROUND_FIX_CAPACITY, 3758c2ecf20Sopenharmony_ci }, 3768c2ecf20Sopenharmony_ci /* iPod 4th generation */ { 3778c2ecf20Sopenharmony_ci .firmware_revision = 0x0a2700, 3788c2ecf20Sopenharmony_ci .model = 0x000021, 3798c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, 3808c2ecf20Sopenharmony_ci }, 3818c2ecf20Sopenharmony_ci /* iPod mini */ { 3828c2ecf20Sopenharmony_ci .firmware_revision = 0x0a2700, 3838c2ecf20Sopenharmony_ci .model = 0x000022, 3848c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, 3858c2ecf20Sopenharmony_ci }, 3868c2ecf20Sopenharmony_ci /* iPod mini */ { 3878c2ecf20Sopenharmony_ci .firmware_revision = 0x0a2700, 3888c2ecf20Sopenharmony_ci .model = 0x000023, 3898c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, 3908c2ecf20Sopenharmony_ci }, 3918c2ecf20Sopenharmony_ci /* iPod Photo */ { 3928c2ecf20Sopenharmony_ci .firmware_revision = 0x0a2700, 3938c2ecf20Sopenharmony_ci .model = 0x00007e, 3948c2ecf20Sopenharmony_ci .workarounds = SBP2_WORKAROUND_FIX_CAPACITY, 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci}; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic void free_orb(struct kref *kref) 3998c2ecf20Sopenharmony_ci{ 4008c2ecf20Sopenharmony_ci struct sbp2_orb *orb = container_of(kref, struct sbp2_orb, kref); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci kfree(orb); 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic void sbp2_status_write(struct fw_card *card, struct fw_request *request, 4068c2ecf20Sopenharmony_ci int tcode, int destination, int source, 4078c2ecf20Sopenharmony_ci int generation, unsigned long long offset, 4088c2ecf20Sopenharmony_ci void *payload, size_t length, void *callback_data) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu = callback_data; 4118c2ecf20Sopenharmony_ci struct sbp2_orb *orb = NULL, *iter; 4128c2ecf20Sopenharmony_ci struct sbp2_status status; 4138c2ecf20Sopenharmony_ci unsigned long flags; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (tcode != TCODE_WRITE_BLOCK_REQUEST || 4168c2ecf20Sopenharmony_ci length < 8 || length > sizeof(status)) { 4178c2ecf20Sopenharmony_ci fw_send_response(card, request, RCODE_TYPE_ERROR); 4188c2ecf20Sopenharmony_ci return; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci status.status = be32_to_cpup(payload); 4228c2ecf20Sopenharmony_ci status.orb_low = be32_to_cpup(payload + 4); 4238c2ecf20Sopenharmony_ci memset(status.data, 0, sizeof(status.data)); 4248c2ecf20Sopenharmony_ci if (length > 8) 4258c2ecf20Sopenharmony_ci memcpy(status.data, payload + 8, length - 8); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci if (STATUS_GET_SOURCE(status) == 2 || STATUS_GET_SOURCE(status) == 3) { 4288c2ecf20Sopenharmony_ci dev_notice(lu_dev(lu), 4298c2ecf20Sopenharmony_ci "non-ORB related status write, not handled\n"); 4308c2ecf20Sopenharmony_ci fw_send_response(card, request, RCODE_COMPLETE); 4318c2ecf20Sopenharmony_ci return; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Lookup the orb corresponding to this status write. */ 4358c2ecf20Sopenharmony_ci spin_lock_irqsave(&lu->tgt->lock, flags); 4368c2ecf20Sopenharmony_ci list_for_each_entry(iter, &lu->orb_list, link) { 4378c2ecf20Sopenharmony_ci if (STATUS_GET_ORB_HIGH(status) == 0 && 4388c2ecf20Sopenharmony_ci STATUS_GET_ORB_LOW(status) == iter->request_bus) { 4398c2ecf20Sopenharmony_ci iter->rcode = RCODE_COMPLETE; 4408c2ecf20Sopenharmony_ci list_del(&iter->link); 4418c2ecf20Sopenharmony_ci orb = iter; 4428c2ecf20Sopenharmony_ci break; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lu->tgt->lock, flags); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (orb) { 4488c2ecf20Sopenharmony_ci orb->callback(orb, &status); 4498c2ecf20Sopenharmony_ci kref_put(&orb->kref, free_orb); /* orb callback reference */ 4508c2ecf20Sopenharmony_ci } else { 4518c2ecf20Sopenharmony_ci dev_err(lu_dev(lu), "status write for unknown ORB\n"); 4528c2ecf20Sopenharmony_ci } 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci fw_send_response(card, request, RCODE_COMPLETE); 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic void complete_transaction(struct fw_card *card, int rcode, 4588c2ecf20Sopenharmony_ci void *payload, size_t length, void *data) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct sbp2_orb *orb = data; 4618c2ecf20Sopenharmony_ci unsigned long flags; 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* 4648c2ecf20Sopenharmony_ci * This is a little tricky. We can get the status write for 4658c2ecf20Sopenharmony_ci * the orb before we get this callback. The status write 4668c2ecf20Sopenharmony_ci * handler above will assume the orb pointer transaction was 4678c2ecf20Sopenharmony_ci * successful and set the rcode to RCODE_COMPLETE for the orb. 4688c2ecf20Sopenharmony_ci * So this callback only sets the rcode if it hasn't already 4698c2ecf20Sopenharmony_ci * been set and only does the cleanup if the transaction 4708c2ecf20Sopenharmony_ci * failed and we didn't already get a status write. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci spin_lock_irqsave(&orb->lu->tgt->lock, flags); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (orb->rcode == -1) 4758c2ecf20Sopenharmony_ci orb->rcode = rcode; 4768c2ecf20Sopenharmony_ci if (orb->rcode != RCODE_COMPLETE) { 4778c2ecf20Sopenharmony_ci list_del(&orb->link); 4788c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&orb->lu->tgt->lock, flags); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci orb->callback(orb, NULL); 4818c2ecf20Sopenharmony_ci kref_put(&orb->kref, free_orb); /* orb callback reference */ 4828c2ecf20Sopenharmony_ci } else { 4838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&orb->lu->tgt->lock, flags); 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci kref_put(&orb->kref, free_orb); /* transaction callback reference */ 4878c2ecf20Sopenharmony_ci} 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cistatic void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu, 4908c2ecf20Sopenharmony_ci int node_id, int generation, u64 offset) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(lu->tgt); 4938c2ecf20Sopenharmony_ci struct sbp2_pointer orb_pointer; 4948c2ecf20Sopenharmony_ci unsigned long flags; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci orb_pointer.high = 0; 4978c2ecf20Sopenharmony_ci orb_pointer.low = cpu_to_be32(orb->request_bus); 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci orb->lu = lu; 5008c2ecf20Sopenharmony_ci spin_lock_irqsave(&lu->tgt->lock, flags); 5018c2ecf20Sopenharmony_ci list_add_tail(&orb->link, &lu->orb_list); 5028c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lu->tgt->lock, flags); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci kref_get(&orb->kref); /* transaction callback reference */ 5058c2ecf20Sopenharmony_ci kref_get(&orb->kref); /* orb callback reference */ 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci fw_send_request(device->card, &orb->t, TCODE_WRITE_BLOCK_REQUEST, 5088c2ecf20Sopenharmony_ci node_id, generation, device->max_speed, offset, 5098c2ecf20Sopenharmony_ci &orb_pointer, 8, complete_transaction, orb); 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int sbp2_cancel_orbs(struct sbp2_logical_unit *lu) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(lu->tgt); 5158c2ecf20Sopenharmony_ci struct sbp2_orb *orb, *next; 5168c2ecf20Sopenharmony_ci struct list_head list; 5178c2ecf20Sopenharmony_ci int retval = -ENOENT; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&list); 5208c2ecf20Sopenharmony_ci spin_lock_irq(&lu->tgt->lock); 5218c2ecf20Sopenharmony_ci list_splice_init(&lu->orb_list, &list); 5228c2ecf20Sopenharmony_ci spin_unlock_irq(&lu->tgt->lock); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci list_for_each_entry_safe(orb, next, &list, link) { 5258c2ecf20Sopenharmony_ci retval = 0; 5268c2ecf20Sopenharmony_ci if (fw_cancel_transaction(device->card, &orb->t) == 0) 5278c2ecf20Sopenharmony_ci continue; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci orb->rcode = RCODE_CANCELLED; 5308c2ecf20Sopenharmony_ci orb->callback(orb, NULL); 5318c2ecf20Sopenharmony_ci kref_put(&orb->kref, free_orb); /* orb callback reference */ 5328c2ecf20Sopenharmony_ci } 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci return retval; 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_cistatic void complete_management_orb(struct sbp2_orb *base_orb, 5388c2ecf20Sopenharmony_ci struct sbp2_status *status) 5398c2ecf20Sopenharmony_ci{ 5408c2ecf20Sopenharmony_ci struct sbp2_management_orb *orb = 5418c2ecf20Sopenharmony_ci container_of(base_orb, struct sbp2_management_orb, base); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (status) 5448c2ecf20Sopenharmony_ci memcpy(&orb->status, status, sizeof(*status)); 5458c2ecf20Sopenharmony_ci complete(&orb->done); 5468c2ecf20Sopenharmony_ci} 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_cistatic int sbp2_send_management_orb(struct sbp2_logical_unit *lu, int node_id, 5498c2ecf20Sopenharmony_ci int generation, int function, 5508c2ecf20Sopenharmony_ci int lun_or_login_id, void *response) 5518c2ecf20Sopenharmony_ci{ 5528c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(lu->tgt); 5538c2ecf20Sopenharmony_ci struct sbp2_management_orb *orb; 5548c2ecf20Sopenharmony_ci unsigned int timeout; 5558c2ecf20Sopenharmony_ci int retval = -ENOMEM; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (function == SBP2_LOGOUT_REQUEST && fw_device_is_shutdown(device)) 5588c2ecf20Sopenharmony_ci return 0; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci orb = kzalloc(sizeof(*orb), GFP_NOIO); 5618c2ecf20Sopenharmony_ci if (orb == NULL) 5628c2ecf20Sopenharmony_ci return -ENOMEM; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci kref_init(&orb->base.kref); 5658c2ecf20Sopenharmony_ci orb->response_bus = 5668c2ecf20Sopenharmony_ci dma_map_single(device->card->device, &orb->response, 5678c2ecf20Sopenharmony_ci sizeof(orb->response), DMA_FROM_DEVICE); 5688c2ecf20Sopenharmony_ci if (dma_mapping_error(device->card->device, orb->response_bus)) 5698c2ecf20Sopenharmony_ci goto fail_mapping_response; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci orb->request.response.high = 0; 5728c2ecf20Sopenharmony_ci orb->request.response.low = cpu_to_be32(orb->response_bus); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci orb->request.misc = cpu_to_be32( 5758c2ecf20Sopenharmony_ci MANAGEMENT_ORB_NOTIFY | 5768c2ecf20Sopenharmony_ci MANAGEMENT_ORB_FUNCTION(function) | 5778c2ecf20Sopenharmony_ci MANAGEMENT_ORB_LUN(lun_or_login_id)); 5788c2ecf20Sopenharmony_ci orb->request.length = cpu_to_be32( 5798c2ecf20Sopenharmony_ci MANAGEMENT_ORB_RESPONSE_LENGTH(sizeof(orb->response))); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci orb->request.status_fifo.high = 5828c2ecf20Sopenharmony_ci cpu_to_be32(lu->address_handler.offset >> 32); 5838c2ecf20Sopenharmony_ci orb->request.status_fifo.low = 5848c2ecf20Sopenharmony_ci cpu_to_be32(lu->address_handler.offset); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci if (function == SBP2_LOGIN_REQUEST) { 5878c2ecf20Sopenharmony_ci /* Ask for 2^2 == 4 seconds reconnect grace period */ 5888c2ecf20Sopenharmony_ci orb->request.misc |= cpu_to_be32( 5898c2ecf20Sopenharmony_ci MANAGEMENT_ORB_RECONNECT(2) | 5908c2ecf20Sopenharmony_ci MANAGEMENT_ORB_EXCLUSIVE(sbp2_param_exclusive_login)); 5918c2ecf20Sopenharmony_ci timeout = lu->tgt->mgt_orb_timeout; 5928c2ecf20Sopenharmony_ci } else { 5938c2ecf20Sopenharmony_ci timeout = SBP2_ORB_TIMEOUT; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci init_completion(&orb->done); 5978c2ecf20Sopenharmony_ci orb->base.callback = complete_management_orb; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci orb->base.request_bus = 6008c2ecf20Sopenharmony_ci dma_map_single(device->card->device, &orb->request, 6018c2ecf20Sopenharmony_ci sizeof(orb->request), DMA_TO_DEVICE); 6028c2ecf20Sopenharmony_ci if (dma_mapping_error(device->card->device, orb->base.request_bus)) 6038c2ecf20Sopenharmony_ci goto fail_mapping_request; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci sbp2_send_orb(&orb->base, lu, node_id, generation, 6068c2ecf20Sopenharmony_ci lu->tgt->management_agent_address); 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci wait_for_completion_timeout(&orb->done, msecs_to_jiffies(timeout)); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci retval = -EIO; 6118c2ecf20Sopenharmony_ci if (sbp2_cancel_orbs(lu) == 0) { 6128c2ecf20Sopenharmony_ci dev_err(lu_dev(lu), "ORB reply timed out, rcode 0x%02x\n", 6138c2ecf20Sopenharmony_ci orb->base.rcode); 6148c2ecf20Sopenharmony_ci goto out; 6158c2ecf20Sopenharmony_ci } 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci if (orb->base.rcode != RCODE_COMPLETE) { 6188c2ecf20Sopenharmony_ci dev_err(lu_dev(lu), "management write failed, rcode 0x%02x\n", 6198c2ecf20Sopenharmony_ci orb->base.rcode); 6208c2ecf20Sopenharmony_ci goto out; 6218c2ecf20Sopenharmony_ci } 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci if (STATUS_GET_RESPONSE(orb->status) != 0 || 6248c2ecf20Sopenharmony_ci STATUS_GET_SBP_STATUS(orb->status) != 0) { 6258c2ecf20Sopenharmony_ci dev_err(lu_dev(lu), "error status: %d:%d\n", 6268c2ecf20Sopenharmony_ci STATUS_GET_RESPONSE(orb->status), 6278c2ecf20Sopenharmony_ci STATUS_GET_SBP_STATUS(orb->status)); 6288c2ecf20Sopenharmony_ci goto out; 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci retval = 0; 6328c2ecf20Sopenharmony_ci out: 6338c2ecf20Sopenharmony_ci dma_unmap_single(device->card->device, orb->base.request_bus, 6348c2ecf20Sopenharmony_ci sizeof(orb->request), DMA_TO_DEVICE); 6358c2ecf20Sopenharmony_ci fail_mapping_request: 6368c2ecf20Sopenharmony_ci dma_unmap_single(device->card->device, orb->response_bus, 6378c2ecf20Sopenharmony_ci sizeof(orb->response), DMA_FROM_DEVICE); 6388c2ecf20Sopenharmony_ci fail_mapping_response: 6398c2ecf20Sopenharmony_ci if (response) 6408c2ecf20Sopenharmony_ci memcpy(response, orb->response, sizeof(orb->response)); 6418c2ecf20Sopenharmony_ci kref_put(&orb->base.kref, free_orb); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci return retval; 6448c2ecf20Sopenharmony_ci} 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_cistatic void sbp2_agent_reset(struct sbp2_logical_unit *lu) 6478c2ecf20Sopenharmony_ci{ 6488c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(lu->tgt); 6498c2ecf20Sopenharmony_ci __be32 d = 0; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST, 6528c2ecf20Sopenharmony_ci lu->tgt->node_id, lu->generation, device->max_speed, 6538c2ecf20Sopenharmony_ci lu->command_block_agent_address + SBP2_AGENT_RESET, 6548c2ecf20Sopenharmony_ci &d, 4); 6558c2ecf20Sopenharmony_ci} 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_cistatic void complete_agent_reset_write_no_wait(struct fw_card *card, 6588c2ecf20Sopenharmony_ci int rcode, void *payload, size_t length, void *data) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci kfree(data); 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu) 6648c2ecf20Sopenharmony_ci{ 6658c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(lu->tgt); 6668c2ecf20Sopenharmony_ci struct fw_transaction *t; 6678c2ecf20Sopenharmony_ci static __be32 d; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci t = kmalloc(sizeof(*t), GFP_ATOMIC); 6708c2ecf20Sopenharmony_ci if (t == NULL) 6718c2ecf20Sopenharmony_ci return; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci fw_send_request(device->card, t, TCODE_WRITE_QUADLET_REQUEST, 6748c2ecf20Sopenharmony_ci lu->tgt->node_id, lu->generation, device->max_speed, 6758c2ecf20Sopenharmony_ci lu->command_block_agent_address + SBP2_AGENT_RESET, 6768c2ecf20Sopenharmony_ci &d, 4, complete_agent_reset_write_no_wait, t); 6778c2ecf20Sopenharmony_ci} 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_cistatic inline void sbp2_allow_block(struct sbp2_target *tgt) 6808c2ecf20Sopenharmony_ci{ 6818c2ecf20Sopenharmony_ci spin_lock_irq(&tgt->lock); 6828c2ecf20Sopenharmony_ci --tgt->dont_block; 6838c2ecf20Sopenharmony_ci spin_unlock_irq(&tgt->lock); 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci/* 6878c2ecf20Sopenharmony_ci * Blocks lu->tgt if all of the following conditions are met: 6888c2ecf20Sopenharmony_ci * - Login, INQUIRY, and high-level SCSI setup of all of the target's 6898c2ecf20Sopenharmony_ci * logical units have been finished (indicated by dont_block == 0). 6908c2ecf20Sopenharmony_ci * - lu->generation is stale. 6918c2ecf20Sopenharmony_ci * 6928c2ecf20Sopenharmony_ci * Note, scsi_block_requests() must be called while holding tgt->lock, 6938c2ecf20Sopenharmony_ci * otherwise it might foil sbp2_[conditionally_]unblock()'s attempt to 6948c2ecf20Sopenharmony_ci * unblock the target. 6958c2ecf20Sopenharmony_ci */ 6968c2ecf20Sopenharmony_cistatic void sbp2_conditionally_block(struct sbp2_logical_unit *lu) 6978c2ecf20Sopenharmony_ci{ 6988c2ecf20Sopenharmony_ci struct sbp2_target *tgt = lu->tgt; 6998c2ecf20Sopenharmony_ci struct fw_card *card = target_parent_device(tgt)->card; 7008c2ecf20Sopenharmony_ci struct Scsi_Host *shost = 7018c2ecf20Sopenharmony_ci container_of((void *)tgt, struct Scsi_Host, hostdata[0]); 7028c2ecf20Sopenharmony_ci unsigned long flags; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci spin_lock_irqsave(&tgt->lock, flags); 7058c2ecf20Sopenharmony_ci if (!tgt->dont_block && !lu->blocked && 7068c2ecf20Sopenharmony_ci lu->generation != card->generation) { 7078c2ecf20Sopenharmony_ci lu->blocked = true; 7088c2ecf20Sopenharmony_ci if (++tgt->blocked == 1) 7098c2ecf20Sopenharmony_ci scsi_block_requests(shost); 7108c2ecf20Sopenharmony_ci } 7118c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&tgt->lock, flags); 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/* 7158c2ecf20Sopenharmony_ci * Unblocks lu->tgt as soon as all its logical units can be unblocked. 7168c2ecf20Sopenharmony_ci * Note, it is harmless to run scsi_unblock_requests() outside the 7178c2ecf20Sopenharmony_ci * tgt->lock protected section. On the other hand, running it inside 7188c2ecf20Sopenharmony_ci * the section might clash with shost->host_lock. 7198c2ecf20Sopenharmony_ci */ 7208c2ecf20Sopenharmony_cistatic void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci struct sbp2_target *tgt = lu->tgt; 7238c2ecf20Sopenharmony_ci struct fw_card *card = target_parent_device(tgt)->card; 7248c2ecf20Sopenharmony_ci struct Scsi_Host *shost = 7258c2ecf20Sopenharmony_ci container_of((void *)tgt, struct Scsi_Host, hostdata[0]); 7268c2ecf20Sopenharmony_ci bool unblock = false; 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci spin_lock_irq(&tgt->lock); 7298c2ecf20Sopenharmony_ci if (lu->blocked && lu->generation == card->generation) { 7308c2ecf20Sopenharmony_ci lu->blocked = false; 7318c2ecf20Sopenharmony_ci unblock = --tgt->blocked == 0; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci spin_unlock_irq(&tgt->lock); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci if (unblock) 7368c2ecf20Sopenharmony_ci scsi_unblock_requests(shost); 7378c2ecf20Sopenharmony_ci} 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci/* 7408c2ecf20Sopenharmony_ci * Prevents future blocking of tgt and unblocks it. 7418c2ecf20Sopenharmony_ci * Note, it is harmless to run scsi_unblock_requests() outside the 7428c2ecf20Sopenharmony_ci * tgt->lock protected section. On the other hand, running it inside 7438c2ecf20Sopenharmony_ci * the section might clash with shost->host_lock. 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_cistatic void sbp2_unblock(struct sbp2_target *tgt) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct Scsi_Host *shost = 7488c2ecf20Sopenharmony_ci container_of((void *)tgt, struct Scsi_Host, hostdata[0]); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci spin_lock_irq(&tgt->lock); 7518c2ecf20Sopenharmony_ci ++tgt->dont_block; 7528c2ecf20Sopenharmony_ci spin_unlock_irq(&tgt->lock); 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_ci scsi_unblock_requests(shost); 7558c2ecf20Sopenharmony_ci} 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic int sbp2_lun2int(u16 lun) 7588c2ecf20Sopenharmony_ci{ 7598c2ecf20Sopenharmony_ci struct scsi_lun eight_bytes_lun; 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci memset(&eight_bytes_lun, 0, sizeof(eight_bytes_lun)); 7628c2ecf20Sopenharmony_ci eight_bytes_lun.scsi_lun[0] = (lun >> 8) & 0xff; 7638c2ecf20Sopenharmony_ci eight_bytes_lun.scsi_lun[1] = lun & 0xff; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci return scsilun_to_int(&eight_bytes_lun); 7668c2ecf20Sopenharmony_ci} 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci/* 7698c2ecf20Sopenharmony_ci * Write retransmit retry values into the BUSY_TIMEOUT register. 7708c2ecf20Sopenharmony_ci * - The single-phase retry protocol is supported by all SBP-2 devices, but the 7718c2ecf20Sopenharmony_ci * default retry_limit value is 0 (i.e. never retry transmission). We write a 7728c2ecf20Sopenharmony_ci * saner value after logging into the device. 7738c2ecf20Sopenharmony_ci * - The dual-phase retry protocol is optional to implement, and if not 7748c2ecf20Sopenharmony_ci * supported, writes to the dual-phase portion of the register will be 7758c2ecf20Sopenharmony_ci * ignored. We try to write the original 1394-1995 default here. 7768c2ecf20Sopenharmony_ci * - In the case of devices that are also SBP-3-compliant, all writes are 7778c2ecf20Sopenharmony_ci * ignored, as the register is read-only, but contains single-phase retry of 7788c2ecf20Sopenharmony_ci * 15, which is what we're trying to set for all SBP-2 device anyway, so this 7798c2ecf20Sopenharmony_ci * write attempt is safe and yields more consistent behavior for all devices. 7808c2ecf20Sopenharmony_ci * 7818c2ecf20Sopenharmony_ci * See section 8.3.2.3.5 of the 1394-1995 spec, section 6.2 of the SBP-2 spec, 7828c2ecf20Sopenharmony_ci * and section 6.4 of the SBP-3 spec for further details. 7838c2ecf20Sopenharmony_ci */ 7848c2ecf20Sopenharmony_cistatic void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(lu->tgt); 7878c2ecf20Sopenharmony_ci __be32 d = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST, 7908c2ecf20Sopenharmony_ci lu->tgt->node_id, lu->generation, device->max_speed, 7918c2ecf20Sopenharmony_ci CSR_REGISTER_BASE + CSR_BUSY_TIMEOUT, &d, 4); 7928c2ecf20Sopenharmony_ci} 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_cistatic void sbp2_reconnect(struct work_struct *work); 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_cistatic void sbp2_login(struct work_struct *work) 7978c2ecf20Sopenharmony_ci{ 7988c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu = 7998c2ecf20Sopenharmony_ci container_of(work, struct sbp2_logical_unit, work.work); 8008c2ecf20Sopenharmony_ci struct sbp2_target *tgt = lu->tgt; 8018c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(tgt); 8028c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 8038c2ecf20Sopenharmony_ci struct scsi_device *sdev; 8048c2ecf20Sopenharmony_ci struct sbp2_login_response response; 8058c2ecf20Sopenharmony_ci int generation, node_id, local_node_id; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci if (fw_device_is_shutdown(device)) 8088c2ecf20Sopenharmony_ci return; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci generation = device->generation; 8118c2ecf20Sopenharmony_ci smp_rmb(); /* node IDs must not be older than generation */ 8128c2ecf20Sopenharmony_ci node_id = device->node_id; 8138c2ecf20Sopenharmony_ci local_node_id = device->card->node_id; 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* If this is a re-login attempt, log out, or we might be rejected. */ 8168c2ecf20Sopenharmony_ci if (lu->has_sdev) 8178c2ecf20Sopenharmony_ci sbp2_send_management_orb(lu, device->node_id, generation, 8188c2ecf20Sopenharmony_ci SBP2_LOGOUT_REQUEST, lu->login_id, NULL); 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (sbp2_send_management_orb(lu, node_id, generation, 8218c2ecf20Sopenharmony_ci SBP2_LOGIN_REQUEST, lu->lun, &response) < 0) { 8228c2ecf20Sopenharmony_ci if (lu->retries++ < 5) { 8238c2ecf20Sopenharmony_ci sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); 8248c2ecf20Sopenharmony_ci } else { 8258c2ecf20Sopenharmony_ci dev_err(tgt_dev(tgt), "failed to login to LUN %04x\n", 8268c2ecf20Sopenharmony_ci lu->lun); 8278c2ecf20Sopenharmony_ci /* Let any waiting I/O fail from now on. */ 8288c2ecf20Sopenharmony_ci sbp2_unblock(lu->tgt); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci return; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci tgt->node_id = node_id; 8348c2ecf20Sopenharmony_ci tgt->address_high = local_node_id << 16; 8358c2ecf20Sopenharmony_ci smp_wmb(); /* node IDs must not be older than generation */ 8368c2ecf20Sopenharmony_ci lu->generation = generation; 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci lu->command_block_agent_address = 8398c2ecf20Sopenharmony_ci ((u64)(be32_to_cpu(response.command_block_agent.high) & 0xffff) 8408c2ecf20Sopenharmony_ci << 32) | be32_to_cpu(response.command_block_agent.low); 8418c2ecf20Sopenharmony_ci lu->login_id = be32_to_cpu(response.misc) & 0xffff; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci dev_notice(tgt_dev(tgt), "logged in to LUN %04x (%d retries)\n", 8448c2ecf20Sopenharmony_ci lu->lun, lu->retries); 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* set appropriate retry limit(s) in BUSY_TIMEOUT register */ 8478c2ecf20Sopenharmony_ci sbp2_set_busy_timeout(lu); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci lu->workfn = sbp2_reconnect; 8508c2ecf20Sopenharmony_ci sbp2_agent_reset(lu); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* This was a re-login. */ 8538c2ecf20Sopenharmony_ci if (lu->has_sdev) { 8548c2ecf20Sopenharmony_ci sbp2_cancel_orbs(lu); 8558c2ecf20Sopenharmony_ci sbp2_conditionally_unblock(lu); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci return; 8588c2ecf20Sopenharmony_ci } 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci if (lu->tgt->workarounds & SBP2_WORKAROUND_DELAY_INQUIRY) 8618c2ecf20Sopenharmony_ci ssleep(SBP2_INQUIRY_DELAY); 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci shost = container_of((void *)tgt, struct Scsi_Host, hostdata[0]); 8648c2ecf20Sopenharmony_ci sdev = __scsi_add_device(shost, 0, 0, sbp2_lun2int(lu->lun), lu); 8658c2ecf20Sopenharmony_ci /* 8668c2ecf20Sopenharmony_ci * FIXME: We are unable to perform reconnects while in sbp2_login(). 8678c2ecf20Sopenharmony_ci * Therefore __scsi_add_device() will get into trouble if a bus reset 8688c2ecf20Sopenharmony_ci * happens in parallel. It will either fail or leave us with an 8698c2ecf20Sopenharmony_ci * unusable sdev. As a workaround we check for this and retry the 8708c2ecf20Sopenharmony_ci * whole login and SCSI probing. 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci /* Reported error during __scsi_add_device() */ 8748c2ecf20Sopenharmony_ci if (IS_ERR(sdev)) 8758c2ecf20Sopenharmony_ci goto out_logout_login; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* Unreported error during __scsi_add_device() */ 8788c2ecf20Sopenharmony_ci smp_rmb(); /* get current card generation */ 8798c2ecf20Sopenharmony_ci if (generation != device->card->generation) { 8808c2ecf20Sopenharmony_ci scsi_remove_device(sdev); 8818c2ecf20Sopenharmony_ci scsi_device_put(sdev); 8828c2ecf20Sopenharmony_ci goto out_logout_login; 8838c2ecf20Sopenharmony_ci } 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ci /* No error during __scsi_add_device() */ 8868c2ecf20Sopenharmony_ci lu->has_sdev = true; 8878c2ecf20Sopenharmony_ci scsi_device_put(sdev); 8888c2ecf20Sopenharmony_ci sbp2_allow_block(tgt); 8898c2ecf20Sopenharmony_ci 8908c2ecf20Sopenharmony_ci return; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci out_logout_login: 8938c2ecf20Sopenharmony_ci smp_rmb(); /* generation may have changed */ 8948c2ecf20Sopenharmony_ci generation = device->generation; 8958c2ecf20Sopenharmony_ci smp_rmb(); /* node_id must not be older than generation */ 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci sbp2_send_management_orb(lu, device->node_id, generation, 8988c2ecf20Sopenharmony_ci SBP2_LOGOUT_REQUEST, lu->login_id, NULL); 8998c2ecf20Sopenharmony_ci /* 9008c2ecf20Sopenharmony_ci * If a bus reset happened, sbp2_update will have requeued 9018c2ecf20Sopenharmony_ci * lu->work already. Reset the work from reconnect to login. 9028c2ecf20Sopenharmony_ci */ 9038c2ecf20Sopenharmony_ci lu->workfn = sbp2_login; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_cistatic void sbp2_reconnect(struct work_struct *work) 9078c2ecf20Sopenharmony_ci{ 9088c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu = 9098c2ecf20Sopenharmony_ci container_of(work, struct sbp2_logical_unit, work.work); 9108c2ecf20Sopenharmony_ci struct sbp2_target *tgt = lu->tgt; 9118c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(tgt); 9128c2ecf20Sopenharmony_ci int generation, node_id, local_node_id; 9138c2ecf20Sopenharmony_ci 9148c2ecf20Sopenharmony_ci if (fw_device_is_shutdown(device)) 9158c2ecf20Sopenharmony_ci return; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci generation = device->generation; 9188c2ecf20Sopenharmony_ci smp_rmb(); /* node IDs must not be older than generation */ 9198c2ecf20Sopenharmony_ci node_id = device->node_id; 9208c2ecf20Sopenharmony_ci local_node_id = device->card->node_id; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (sbp2_send_management_orb(lu, node_id, generation, 9238c2ecf20Sopenharmony_ci SBP2_RECONNECT_REQUEST, 9248c2ecf20Sopenharmony_ci lu->login_id, NULL) < 0) { 9258c2ecf20Sopenharmony_ci /* 9268c2ecf20Sopenharmony_ci * If reconnect was impossible even though we are in the 9278c2ecf20Sopenharmony_ci * current generation, fall back and try to log in again. 9288c2ecf20Sopenharmony_ci * 9298c2ecf20Sopenharmony_ci * We could check for "Function rejected" status, but 9308c2ecf20Sopenharmony_ci * looking at the bus generation as simpler and more general. 9318c2ecf20Sopenharmony_ci */ 9328c2ecf20Sopenharmony_ci smp_rmb(); /* get current card generation */ 9338c2ecf20Sopenharmony_ci if (generation == device->card->generation || 9348c2ecf20Sopenharmony_ci lu->retries++ >= 5) { 9358c2ecf20Sopenharmony_ci dev_err(tgt_dev(tgt), "failed to reconnect\n"); 9368c2ecf20Sopenharmony_ci lu->retries = 0; 9378c2ecf20Sopenharmony_ci lu->workfn = sbp2_login; 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci return; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci tgt->node_id = node_id; 9458c2ecf20Sopenharmony_ci tgt->address_high = local_node_id << 16; 9468c2ecf20Sopenharmony_ci smp_wmb(); /* node IDs must not be older than generation */ 9478c2ecf20Sopenharmony_ci lu->generation = generation; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci dev_notice(tgt_dev(tgt), "reconnected to LUN %04x (%d retries)\n", 9508c2ecf20Sopenharmony_ci lu->lun, lu->retries); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci sbp2_agent_reset(lu); 9538c2ecf20Sopenharmony_ci sbp2_cancel_orbs(lu); 9548c2ecf20Sopenharmony_ci sbp2_conditionally_unblock(lu); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic void sbp2_lu_workfn(struct work_struct *work) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu = container_of(to_delayed_work(work), 9608c2ecf20Sopenharmony_ci struct sbp2_logical_unit, work); 9618c2ecf20Sopenharmony_ci lu->workfn(work); 9628c2ecf20Sopenharmony_ci} 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_cistatic int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry) 9658c2ecf20Sopenharmony_ci{ 9668c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci lu = kmalloc(sizeof(*lu), GFP_KERNEL); 9698c2ecf20Sopenharmony_ci if (!lu) 9708c2ecf20Sopenharmony_ci return -ENOMEM; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci lu->address_handler.length = 0x100; 9738c2ecf20Sopenharmony_ci lu->address_handler.address_callback = sbp2_status_write; 9748c2ecf20Sopenharmony_ci lu->address_handler.callback_data = lu; 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ci if (fw_core_add_address_handler(&lu->address_handler, 9778c2ecf20Sopenharmony_ci &fw_high_memory_region) < 0) { 9788c2ecf20Sopenharmony_ci kfree(lu); 9798c2ecf20Sopenharmony_ci return -ENOMEM; 9808c2ecf20Sopenharmony_ci } 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci lu->tgt = tgt; 9838c2ecf20Sopenharmony_ci lu->lun = lun_entry & 0xffff; 9848c2ecf20Sopenharmony_ci lu->login_id = INVALID_LOGIN_ID; 9858c2ecf20Sopenharmony_ci lu->retries = 0; 9868c2ecf20Sopenharmony_ci lu->has_sdev = false; 9878c2ecf20Sopenharmony_ci lu->blocked = false; 9888c2ecf20Sopenharmony_ci ++tgt->dont_block; 9898c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&lu->orb_list); 9908c2ecf20Sopenharmony_ci lu->workfn = sbp2_login; 9918c2ecf20Sopenharmony_ci INIT_DELAYED_WORK(&lu->work, sbp2_lu_workfn); 9928c2ecf20Sopenharmony_ci 9938c2ecf20Sopenharmony_ci list_add_tail(&lu->link, &tgt->lu_list); 9948c2ecf20Sopenharmony_ci return 0; 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_cistatic void sbp2_get_unit_unique_id(struct sbp2_target *tgt, 9988c2ecf20Sopenharmony_ci const u32 *leaf) 9998c2ecf20Sopenharmony_ci{ 10008c2ecf20Sopenharmony_ci if ((leaf[0] & 0xffff0000) == 0x00020000) 10018c2ecf20Sopenharmony_ci tgt->guid = (u64)leaf[1] << 32 | leaf[2]; 10028c2ecf20Sopenharmony_ci} 10038c2ecf20Sopenharmony_ci 10048c2ecf20Sopenharmony_cistatic int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, 10058c2ecf20Sopenharmony_ci const u32 *directory) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci struct fw_csr_iterator ci; 10088c2ecf20Sopenharmony_ci int key, value; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci fw_csr_iterator_init(&ci, directory); 10118c2ecf20Sopenharmony_ci while (fw_csr_iterator_next(&ci, &key, &value)) 10128c2ecf20Sopenharmony_ci if (key == SBP2_CSR_LOGICAL_UNIT_NUMBER && 10138c2ecf20Sopenharmony_ci sbp2_add_logical_unit(tgt, value) < 0) 10148c2ecf20Sopenharmony_ci return -ENOMEM; 10158c2ecf20Sopenharmony_ci return 0; 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic int sbp2_scan_unit_dir(struct sbp2_target *tgt, const u32 *directory, 10198c2ecf20Sopenharmony_ci u32 *model, u32 *firmware_revision) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct fw_csr_iterator ci; 10228c2ecf20Sopenharmony_ci int key, value; 10238c2ecf20Sopenharmony_ci 10248c2ecf20Sopenharmony_ci fw_csr_iterator_init(&ci, directory); 10258c2ecf20Sopenharmony_ci while (fw_csr_iterator_next(&ci, &key, &value)) { 10268c2ecf20Sopenharmony_ci switch (key) { 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci case CSR_DEPENDENT_INFO | CSR_OFFSET: 10298c2ecf20Sopenharmony_ci tgt->management_agent_address = 10308c2ecf20Sopenharmony_ci CSR_REGISTER_BASE + 4 * value; 10318c2ecf20Sopenharmony_ci break; 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci case CSR_DIRECTORY_ID: 10348c2ecf20Sopenharmony_ci tgt->directory_id = value; 10358c2ecf20Sopenharmony_ci break; 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci case CSR_MODEL: 10388c2ecf20Sopenharmony_ci *model = value; 10398c2ecf20Sopenharmony_ci break; 10408c2ecf20Sopenharmony_ci 10418c2ecf20Sopenharmony_ci case SBP2_CSR_FIRMWARE_REVISION: 10428c2ecf20Sopenharmony_ci *firmware_revision = value; 10438c2ecf20Sopenharmony_ci break; 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci case SBP2_CSR_UNIT_CHARACTERISTICS: 10468c2ecf20Sopenharmony_ci /* the timeout value is stored in 500ms units */ 10478c2ecf20Sopenharmony_ci tgt->mgt_orb_timeout = (value >> 8 & 0xff) * 500; 10488c2ecf20Sopenharmony_ci break; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci case SBP2_CSR_LOGICAL_UNIT_NUMBER: 10518c2ecf20Sopenharmony_ci if (sbp2_add_logical_unit(tgt, value) < 0) 10528c2ecf20Sopenharmony_ci return -ENOMEM; 10538c2ecf20Sopenharmony_ci break; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci case SBP2_CSR_UNIT_UNIQUE_ID: 10568c2ecf20Sopenharmony_ci sbp2_get_unit_unique_id(tgt, ci.p - 1 + value); 10578c2ecf20Sopenharmony_ci break; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci case SBP2_CSR_LOGICAL_UNIT_DIRECTORY: 10608c2ecf20Sopenharmony_ci /* Adjust for the increment in the iterator */ 10618c2ecf20Sopenharmony_ci if (sbp2_scan_logical_unit_dir(tgt, ci.p - 1 + value) < 0) 10628c2ecf20Sopenharmony_ci return -ENOMEM; 10638c2ecf20Sopenharmony_ci break; 10648c2ecf20Sopenharmony_ci } 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci return 0; 10678c2ecf20Sopenharmony_ci} 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci/* 10708c2ecf20Sopenharmony_ci * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be 10718c2ecf20Sopenharmony_ci * provided in the config rom. Most devices do provide a value, which 10728c2ecf20Sopenharmony_ci * we'll use for login management orbs, but with some sane limits. 10738c2ecf20Sopenharmony_ci */ 10748c2ecf20Sopenharmony_cistatic void sbp2_clamp_management_orb_timeout(struct sbp2_target *tgt) 10758c2ecf20Sopenharmony_ci{ 10768c2ecf20Sopenharmony_ci unsigned int timeout = tgt->mgt_orb_timeout; 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci if (timeout > 40000) 10798c2ecf20Sopenharmony_ci dev_notice(tgt_dev(tgt), "%ds mgt_ORB_timeout limited to 40s\n", 10808c2ecf20Sopenharmony_ci timeout / 1000); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci tgt->mgt_orb_timeout = clamp_val(timeout, 5000, 40000); 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model, 10868c2ecf20Sopenharmony_ci u32 firmware_revision) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci int i; 10898c2ecf20Sopenharmony_ci unsigned int w = sbp2_param_workarounds; 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci if (w) 10928c2ecf20Sopenharmony_ci dev_notice(tgt_dev(tgt), 10938c2ecf20Sopenharmony_ci "Please notify linux1394-devel@lists.sf.net " 10948c2ecf20Sopenharmony_ci "if you need the workarounds parameter\n"); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci if (w & SBP2_WORKAROUND_OVERRIDE) 10978c2ecf20Sopenharmony_ci goto out; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) { 11008c2ecf20Sopenharmony_ci 11018c2ecf20Sopenharmony_ci if (sbp2_workarounds_table[i].firmware_revision != 11028c2ecf20Sopenharmony_ci (firmware_revision & 0xffffff00)) 11038c2ecf20Sopenharmony_ci continue; 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci if (sbp2_workarounds_table[i].model != model && 11068c2ecf20Sopenharmony_ci sbp2_workarounds_table[i].model != SBP2_ROM_VALUE_WILDCARD) 11078c2ecf20Sopenharmony_ci continue; 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci w |= sbp2_workarounds_table[i].workarounds; 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci out: 11138c2ecf20Sopenharmony_ci if (w) 11148c2ecf20Sopenharmony_ci dev_notice(tgt_dev(tgt), "workarounds 0x%x " 11158c2ecf20Sopenharmony_ci "(firmware_revision 0x%06x, model_id 0x%06x)\n", 11168c2ecf20Sopenharmony_ci w, firmware_revision, model); 11178c2ecf20Sopenharmony_ci tgt->workarounds = w; 11188c2ecf20Sopenharmony_ci} 11198c2ecf20Sopenharmony_ci 11208c2ecf20Sopenharmony_cistatic struct scsi_host_template scsi_driver_template; 11218c2ecf20Sopenharmony_cistatic void sbp2_remove(struct fw_unit *unit); 11228c2ecf20Sopenharmony_ci 11238c2ecf20Sopenharmony_cistatic int sbp2_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) 11248c2ecf20Sopenharmony_ci{ 11258c2ecf20Sopenharmony_ci struct fw_device *device = fw_parent_device(unit); 11268c2ecf20Sopenharmony_ci struct sbp2_target *tgt; 11278c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu; 11288c2ecf20Sopenharmony_ci struct Scsi_Host *shost; 11298c2ecf20Sopenharmony_ci u32 model, firmware_revision; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci /* cannot (or should not) handle targets on the local node */ 11328c2ecf20Sopenharmony_ci if (device->is_local) 11338c2ecf20Sopenharmony_ci return -ENODEV; 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci shost = scsi_host_alloc(&scsi_driver_template, sizeof(*tgt)); 11368c2ecf20Sopenharmony_ci if (shost == NULL) 11378c2ecf20Sopenharmony_ci return -ENOMEM; 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci tgt = (struct sbp2_target *)shost->hostdata; 11408c2ecf20Sopenharmony_ci dev_set_drvdata(&unit->device, tgt); 11418c2ecf20Sopenharmony_ci tgt->unit = unit; 11428c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&tgt->lu_list); 11438c2ecf20Sopenharmony_ci spin_lock_init(&tgt->lock); 11448c2ecf20Sopenharmony_ci tgt->guid = (u64)device->config_rom[3] << 32 | device->config_rom[4]; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci if (fw_device_enable_phys_dma(device) < 0) 11478c2ecf20Sopenharmony_ci goto fail_shost_put; 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci shost->max_cmd_len = SBP2_MAX_CDB_SIZE; 11508c2ecf20Sopenharmony_ci 11518c2ecf20Sopenharmony_ci if (scsi_add_host_with_dma(shost, &unit->device, 11528c2ecf20Sopenharmony_ci device->card->device) < 0) 11538c2ecf20Sopenharmony_ci goto fail_shost_put; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci /* implicit directory ID */ 11568c2ecf20Sopenharmony_ci tgt->directory_id = ((unit->directory - device->config_rom) * 4 11578c2ecf20Sopenharmony_ci + CSR_CONFIG_ROM) & 0xffffff; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci firmware_revision = SBP2_ROM_VALUE_MISSING; 11608c2ecf20Sopenharmony_ci model = SBP2_ROM_VALUE_MISSING; 11618c2ecf20Sopenharmony_ci 11628c2ecf20Sopenharmony_ci if (sbp2_scan_unit_dir(tgt, unit->directory, &model, 11638c2ecf20Sopenharmony_ci &firmware_revision) < 0) 11648c2ecf20Sopenharmony_ci goto fail_remove; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci sbp2_clamp_management_orb_timeout(tgt); 11678c2ecf20Sopenharmony_ci sbp2_init_workarounds(tgt, model, firmware_revision); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci /* 11708c2ecf20Sopenharmony_ci * At S100 we can do 512 bytes per packet, at S200 1024 bytes, 11718c2ecf20Sopenharmony_ci * and so on up to 4096 bytes. The SBP-2 max_payload field 11728c2ecf20Sopenharmony_ci * specifies the max payload size as 2 ^ (max_payload + 2), so 11738c2ecf20Sopenharmony_ci * if we set this to max_speed + 7, we get the right value. 11748c2ecf20Sopenharmony_ci */ 11758c2ecf20Sopenharmony_ci tgt->max_payload = min3(device->max_speed + 7, 10U, 11768c2ecf20Sopenharmony_ci device->card->max_receive - 1); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* Do the login in a workqueue so we can easily reschedule retries. */ 11798c2ecf20Sopenharmony_ci list_for_each_entry(lu, &tgt->lu_list, link) 11808c2ecf20Sopenharmony_ci sbp2_queue_work(lu, DIV_ROUND_UP(HZ, 5)); 11818c2ecf20Sopenharmony_ci 11828c2ecf20Sopenharmony_ci return 0; 11838c2ecf20Sopenharmony_ci 11848c2ecf20Sopenharmony_ci fail_remove: 11858c2ecf20Sopenharmony_ci sbp2_remove(unit); 11868c2ecf20Sopenharmony_ci return -ENOMEM; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci fail_shost_put: 11898c2ecf20Sopenharmony_ci scsi_host_put(shost); 11908c2ecf20Sopenharmony_ci return -ENOMEM; 11918c2ecf20Sopenharmony_ci} 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_cistatic void sbp2_update(struct fw_unit *unit) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci struct sbp2_target *tgt = dev_get_drvdata(&unit->device); 11968c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu; 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci fw_device_enable_phys_dma(fw_parent_device(unit)); 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_ci /* 12018c2ecf20Sopenharmony_ci * Fw-core serializes sbp2_update() against sbp2_remove(). 12028c2ecf20Sopenharmony_ci * Iteration over tgt->lu_list is therefore safe here. 12038c2ecf20Sopenharmony_ci */ 12048c2ecf20Sopenharmony_ci list_for_each_entry(lu, &tgt->lu_list, link) { 12058c2ecf20Sopenharmony_ci sbp2_conditionally_block(lu); 12068c2ecf20Sopenharmony_ci lu->retries = 0; 12078c2ecf20Sopenharmony_ci sbp2_queue_work(lu, 0); 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci} 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_cistatic void sbp2_remove(struct fw_unit *unit) 12128c2ecf20Sopenharmony_ci{ 12138c2ecf20Sopenharmony_ci struct fw_device *device = fw_parent_device(unit); 12148c2ecf20Sopenharmony_ci struct sbp2_target *tgt = dev_get_drvdata(&unit->device); 12158c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu, *next; 12168c2ecf20Sopenharmony_ci struct Scsi_Host *shost = 12178c2ecf20Sopenharmony_ci container_of((void *)tgt, struct Scsi_Host, hostdata[0]); 12188c2ecf20Sopenharmony_ci struct scsi_device *sdev; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* prevent deadlocks */ 12218c2ecf20Sopenharmony_ci sbp2_unblock(tgt); 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ci list_for_each_entry_safe(lu, next, &tgt->lu_list, link) { 12248c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&lu->work); 12258c2ecf20Sopenharmony_ci sdev = scsi_device_lookup(shost, 0, 0, sbp2_lun2int(lu->lun)); 12268c2ecf20Sopenharmony_ci if (sdev) { 12278c2ecf20Sopenharmony_ci scsi_remove_device(sdev); 12288c2ecf20Sopenharmony_ci scsi_device_put(sdev); 12298c2ecf20Sopenharmony_ci } 12308c2ecf20Sopenharmony_ci if (lu->login_id != INVALID_LOGIN_ID) { 12318c2ecf20Sopenharmony_ci int generation, node_id; 12328c2ecf20Sopenharmony_ci /* 12338c2ecf20Sopenharmony_ci * tgt->node_id may be obsolete here if we failed 12348c2ecf20Sopenharmony_ci * during initial login or after a bus reset where 12358c2ecf20Sopenharmony_ci * the topology changed. 12368c2ecf20Sopenharmony_ci */ 12378c2ecf20Sopenharmony_ci generation = device->generation; 12388c2ecf20Sopenharmony_ci smp_rmb(); /* node_id vs. generation */ 12398c2ecf20Sopenharmony_ci node_id = device->node_id; 12408c2ecf20Sopenharmony_ci sbp2_send_management_orb(lu, node_id, generation, 12418c2ecf20Sopenharmony_ci SBP2_LOGOUT_REQUEST, 12428c2ecf20Sopenharmony_ci lu->login_id, NULL); 12438c2ecf20Sopenharmony_ci } 12448c2ecf20Sopenharmony_ci fw_core_remove_address_handler(&lu->address_handler); 12458c2ecf20Sopenharmony_ci list_del(&lu->link); 12468c2ecf20Sopenharmony_ci kfree(lu); 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci scsi_remove_host(shost); 12498c2ecf20Sopenharmony_ci dev_notice(&unit->device, "released target %d:0:0\n", shost->host_no); 12508c2ecf20Sopenharmony_ci 12518c2ecf20Sopenharmony_ci scsi_host_put(shost); 12528c2ecf20Sopenharmony_ci} 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci#define SBP2_UNIT_SPEC_ID_ENTRY 0x0000609e 12558c2ecf20Sopenharmony_ci#define SBP2_SW_VERSION_ENTRY 0x00010483 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic const struct ieee1394_device_id sbp2_id_table[] = { 12588c2ecf20Sopenharmony_ci { 12598c2ecf20Sopenharmony_ci .match_flags = IEEE1394_MATCH_SPECIFIER_ID | 12608c2ecf20Sopenharmony_ci IEEE1394_MATCH_VERSION, 12618c2ecf20Sopenharmony_ci .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY, 12628c2ecf20Sopenharmony_ci .version = SBP2_SW_VERSION_ENTRY, 12638c2ecf20Sopenharmony_ci }, 12648c2ecf20Sopenharmony_ci { } 12658c2ecf20Sopenharmony_ci}; 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_cistatic struct fw_driver sbp2_driver = { 12688c2ecf20Sopenharmony_ci .driver = { 12698c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12708c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 12718c2ecf20Sopenharmony_ci .bus = &fw_bus_type, 12728c2ecf20Sopenharmony_ci }, 12738c2ecf20Sopenharmony_ci .probe = sbp2_probe, 12748c2ecf20Sopenharmony_ci .update = sbp2_update, 12758c2ecf20Sopenharmony_ci .remove = sbp2_remove, 12768c2ecf20Sopenharmony_ci .id_table = sbp2_id_table, 12778c2ecf20Sopenharmony_ci}; 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_cistatic void sbp2_unmap_scatterlist(struct device *card_device, 12808c2ecf20Sopenharmony_ci struct sbp2_command_orb *orb) 12818c2ecf20Sopenharmony_ci{ 12828c2ecf20Sopenharmony_ci scsi_dma_unmap(orb->cmd); 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci if (orb->request.misc & cpu_to_be32(COMMAND_ORB_PAGE_TABLE_PRESENT)) 12858c2ecf20Sopenharmony_ci dma_unmap_single(card_device, orb->page_table_bus, 12868c2ecf20Sopenharmony_ci sizeof(orb->page_table), DMA_TO_DEVICE); 12878c2ecf20Sopenharmony_ci} 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_cistatic unsigned int sbp2_status_to_sense_data(u8 *sbp2_status, u8 *sense_data) 12908c2ecf20Sopenharmony_ci{ 12918c2ecf20Sopenharmony_ci int sam_status; 12928c2ecf20Sopenharmony_ci int sfmt = (sbp2_status[0] >> 6) & 0x03; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (sfmt == 2 || sfmt == 3) { 12958c2ecf20Sopenharmony_ci /* 12968c2ecf20Sopenharmony_ci * Reserved for future standardization (2) or 12978c2ecf20Sopenharmony_ci * Status block format vendor-dependent (3) 12988c2ecf20Sopenharmony_ci */ 12998c2ecf20Sopenharmony_ci return DID_ERROR << 16; 13008c2ecf20Sopenharmony_ci } 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci sense_data[0] = 0x70 | sfmt | (sbp2_status[1] & 0x80); 13038c2ecf20Sopenharmony_ci sense_data[1] = 0x0; 13048c2ecf20Sopenharmony_ci sense_data[2] = ((sbp2_status[1] << 1) & 0xe0) | (sbp2_status[1] & 0x0f); 13058c2ecf20Sopenharmony_ci sense_data[3] = sbp2_status[4]; 13068c2ecf20Sopenharmony_ci sense_data[4] = sbp2_status[5]; 13078c2ecf20Sopenharmony_ci sense_data[5] = sbp2_status[6]; 13088c2ecf20Sopenharmony_ci sense_data[6] = sbp2_status[7]; 13098c2ecf20Sopenharmony_ci sense_data[7] = 10; 13108c2ecf20Sopenharmony_ci sense_data[8] = sbp2_status[8]; 13118c2ecf20Sopenharmony_ci sense_data[9] = sbp2_status[9]; 13128c2ecf20Sopenharmony_ci sense_data[10] = sbp2_status[10]; 13138c2ecf20Sopenharmony_ci sense_data[11] = sbp2_status[11]; 13148c2ecf20Sopenharmony_ci sense_data[12] = sbp2_status[2]; 13158c2ecf20Sopenharmony_ci sense_data[13] = sbp2_status[3]; 13168c2ecf20Sopenharmony_ci sense_data[14] = sbp2_status[12]; 13178c2ecf20Sopenharmony_ci sense_data[15] = sbp2_status[13]; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci sam_status = sbp2_status[0] & 0x3f; 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci switch (sam_status) { 13228c2ecf20Sopenharmony_ci case SAM_STAT_GOOD: 13238c2ecf20Sopenharmony_ci case SAM_STAT_CHECK_CONDITION: 13248c2ecf20Sopenharmony_ci case SAM_STAT_CONDITION_MET: 13258c2ecf20Sopenharmony_ci case SAM_STAT_BUSY: 13268c2ecf20Sopenharmony_ci case SAM_STAT_RESERVATION_CONFLICT: 13278c2ecf20Sopenharmony_ci case SAM_STAT_COMMAND_TERMINATED: 13288c2ecf20Sopenharmony_ci return DID_OK << 16 | sam_status; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci default: 13318c2ecf20Sopenharmony_ci return DID_ERROR << 16; 13328c2ecf20Sopenharmony_ci } 13338c2ecf20Sopenharmony_ci} 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_cistatic void complete_command_orb(struct sbp2_orb *base_orb, 13368c2ecf20Sopenharmony_ci struct sbp2_status *status) 13378c2ecf20Sopenharmony_ci{ 13388c2ecf20Sopenharmony_ci struct sbp2_command_orb *orb = 13398c2ecf20Sopenharmony_ci container_of(base_orb, struct sbp2_command_orb, base); 13408c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(base_orb->lu->tgt); 13418c2ecf20Sopenharmony_ci int result; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci if (status != NULL) { 13448c2ecf20Sopenharmony_ci if (STATUS_GET_DEAD(*status)) 13458c2ecf20Sopenharmony_ci sbp2_agent_reset_no_wait(base_orb->lu); 13468c2ecf20Sopenharmony_ci 13478c2ecf20Sopenharmony_ci switch (STATUS_GET_RESPONSE(*status)) { 13488c2ecf20Sopenharmony_ci case SBP2_STATUS_REQUEST_COMPLETE: 13498c2ecf20Sopenharmony_ci result = DID_OK << 16; 13508c2ecf20Sopenharmony_ci break; 13518c2ecf20Sopenharmony_ci case SBP2_STATUS_TRANSPORT_FAILURE: 13528c2ecf20Sopenharmony_ci result = DID_BUS_BUSY << 16; 13538c2ecf20Sopenharmony_ci break; 13548c2ecf20Sopenharmony_ci case SBP2_STATUS_ILLEGAL_REQUEST: 13558c2ecf20Sopenharmony_ci case SBP2_STATUS_VENDOR_DEPENDENT: 13568c2ecf20Sopenharmony_ci default: 13578c2ecf20Sopenharmony_ci result = DID_ERROR << 16; 13588c2ecf20Sopenharmony_ci break; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (result == DID_OK << 16 && STATUS_GET_LEN(*status) > 1) 13628c2ecf20Sopenharmony_ci result = sbp2_status_to_sense_data(STATUS_GET_DATA(*status), 13638c2ecf20Sopenharmony_ci orb->cmd->sense_buffer); 13648c2ecf20Sopenharmony_ci } else { 13658c2ecf20Sopenharmony_ci /* 13668c2ecf20Sopenharmony_ci * If the orb completes with status == NULL, something 13678c2ecf20Sopenharmony_ci * went wrong, typically a bus reset happened mid-orb 13688c2ecf20Sopenharmony_ci * or when sending the write (less likely). 13698c2ecf20Sopenharmony_ci */ 13708c2ecf20Sopenharmony_ci result = DID_BUS_BUSY << 16; 13718c2ecf20Sopenharmony_ci sbp2_conditionally_block(base_orb->lu); 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci dma_unmap_single(device->card->device, orb->base.request_bus, 13758c2ecf20Sopenharmony_ci sizeof(orb->request), DMA_TO_DEVICE); 13768c2ecf20Sopenharmony_ci sbp2_unmap_scatterlist(device->card->device, orb); 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci orb->cmd->result = result; 13798c2ecf20Sopenharmony_ci orb->cmd->scsi_done(orb->cmd); 13808c2ecf20Sopenharmony_ci} 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_cistatic int sbp2_map_scatterlist(struct sbp2_command_orb *orb, 13838c2ecf20Sopenharmony_ci struct fw_device *device, struct sbp2_logical_unit *lu) 13848c2ecf20Sopenharmony_ci{ 13858c2ecf20Sopenharmony_ci struct scatterlist *sg = scsi_sglist(orb->cmd); 13868c2ecf20Sopenharmony_ci int i, n; 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci n = scsi_dma_map(orb->cmd); 13898c2ecf20Sopenharmony_ci if (n <= 0) 13908c2ecf20Sopenharmony_ci goto fail; 13918c2ecf20Sopenharmony_ci 13928c2ecf20Sopenharmony_ci /* 13938c2ecf20Sopenharmony_ci * Handle the special case where there is only one element in 13948c2ecf20Sopenharmony_ci * the scatter list by converting it to an immediate block 13958c2ecf20Sopenharmony_ci * request. This is also a workaround for broken devices such 13968c2ecf20Sopenharmony_ci * as the second generation iPod which doesn't support page 13978c2ecf20Sopenharmony_ci * tables. 13988c2ecf20Sopenharmony_ci */ 13998c2ecf20Sopenharmony_ci if (n == 1) { 14008c2ecf20Sopenharmony_ci orb->request.data_descriptor.high = 14018c2ecf20Sopenharmony_ci cpu_to_be32(lu->tgt->address_high); 14028c2ecf20Sopenharmony_ci orb->request.data_descriptor.low = 14038c2ecf20Sopenharmony_ci cpu_to_be32(sg_dma_address(sg)); 14048c2ecf20Sopenharmony_ci orb->request.misc |= 14058c2ecf20Sopenharmony_ci cpu_to_be32(COMMAND_ORB_DATA_SIZE(sg_dma_len(sg))); 14068c2ecf20Sopenharmony_ci return 0; 14078c2ecf20Sopenharmony_ci } 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci for_each_sg(sg, sg, n, i) { 14108c2ecf20Sopenharmony_ci orb->page_table[i].high = cpu_to_be32(sg_dma_len(sg) << 16); 14118c2ecf20Sopenharmony_ci orb->page_table[i].low = cpu_to_be32(sg_dma_address(sg)); 14128c2ecf20Sopenharmony_ci } 14138c2ecf20Sopenharmony_ci 14148c2ecf20Sopenharmony_ci orb->page_table_bus = 14158c2ecf20Sopenharmony_ci dma_map_single(device->card->device, orb->page_table, 14168c2ecf20Sopenharmony_ci sizeof(orb->page_table), DMA_TO_DEVICE); 14178c2ecf20Sopenharmony_ci if (dma_mapping_error(device->card->device, orb->page_table_bus)) 14188c2ecf20Sopenharmony_ci goto fail_page_table; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci /* 14218c2ecf20Sopenharmony_ci * The data_descriptor pointer is the one case where we need 14228c2ecf20Sopenharmony_ci * to fill in the node ID part of the address. All other 14238c2ecf20Sopenharmony_ci * pointers assume that the data referenced reside on the 14248c2ecf20Sopenharmony_ci * initiator (i.e. us), but data_descriptor can refer to data 14258c2ecf20Sopenharmony_ci * on other nodes so we need to put our ID in descriptor.high. 14268c2ecf20Sopenharmony_ci */ 14278c2ecf20Sopenharmony_ci orb->request.data_descriptor.high = cpu_to_be32(lu->tgt->address_high); 14288c2ecf20Sopenharmony_ci orb->request.data_descriptor.low = cpu_to_be32(orb->page_table_bus); 14298c2ecf20Sopenharmony_ci orb->request.misc |= cpu_to_be32(COMMAND_ORB_PAGE_TABLE_PRESENT | 14308c2ecf20Sopenharmony_ci COMMAND_ORB_DATA_SIZE(n)); 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_ci return 0; 14338c2ecf20Sopenharmony_ci 14348c2ecf20Sopenharmony_ci fail_page_table: 14358c2ecf20Sopenharmony_ci scsi_dma_unmap(orb->cmd); 14368c2ecf20Sopenharmony_ci fail: 14378c2ecf20Sopenharmony_ci return -ENOMEM; 14388c2ecf20Sopenharmony_ci} 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci/* SCSI stack integration */ 14418c2ecf20Sopenharmony_ci 14428c2ecf20Sopenharmony_cistatic int sbp2_scsi_queuecommand(struct Scsi_Host *shost, 14438c2ecf20Sopenharmony_ci struct scsi_cmnd *cmd) 14448c2ecf20Sopenharmony_ci{ 14458c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu = cmd->device->hostdata; 14468c2ecf20Sopenharmony_ci struct fw_device *device = target_parent_device(lu->tgt); 14478c2ecf20Sopenharmony_ci struct sbp2_command_orb *orb; 14488c2ecf20Sopenharmony_ci int generation, retval = SCSI_MLQUEUE_HOST_BUSY; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci orb = kzalloc(sizeof(*orb), GFP_ATOMIC); 14518c2ecf20Sopenharmony_ci if (orb == NULL) 14528c2ecf20Sopenharmony_ci return SCSI_MLQUEUE_HOST_BUSY; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci /* Initialize rcode to something not RCODE_COMPLETE. */ 14558c2ecf20Sopenharmony_ci orb->base.rcode = -1; 14568c2ecf20Sopenharmony_ci kref_init(&orb->base.kref); 14578c2ecf20Sopenharmony_ci orb->cmd = cmd; 14588c2ecf20Sopenharmony_ci orb->request.next.high = cpu_to_be32(SBP2_ORB_NULL); 14598c2ecf20Sopenharmony_ci orb->request.misc = cpu_to_be32( 14608c2ecf20Sopenharmony_ci COMMAND_ORB_MAX_PAYLOAD(lu->tgt->max_payload) | 14618c2ecf20Sopenharmony_ci COMMAND_ORB_SPEED(device->max_speed) | 14628c2ecf20Sopenharmony_ci COMMAND_ORB_NOTIFY); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_ci if (cmd->sc_data_direction == DMA_FROM_DEVICE) 14658c2ecf20Sopenharmony_ci orb->request.misc |= cpu_to_be32(COMMAND_ORB_DIRECTION); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci generation = device->generation; 14688c2ecf20Sopenharmony_ci smp_rmb(); /* sbp2_map_scatterlist looks at tgt->address_high */ 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (scsi_sg_count(cmd) && sbp2_map_scatterlist(orb, device, lu) < 0) 14718c2ecf20Sopenharmony_ci goto out; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci memcpy(orb->request.command_block, cmd->cmnd, cmd->cmd_len); 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci orb->base.callback = complete_command_orb; 14768c2ecf20Sopenharmony_ci orb->base.request_bus = 14778c2ecf20Sopenharmony_ci dma_map_single(device->card->device, &orb->request, 14788c2ecf20Sopenharmony_ci sizeof(orb->request), DMA_TO_DEVICE); 14798c2ecf20Sopenharmony_ci if (dma_mapping_error(device->card->device, orb->base.request_bus)) { 14808c2ecf20Sopenharmony_ci sbp2_unmap_scatterlist(device->card->device, orb); 14818c2ecf20Sopenharmony_ci goto out; 14828c2ecf20Sopenharmony_ci } 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_ci sbp2_send_orb(&orb->base, lu, lu->tgt->node_id, generation, 14858c2ecf20Sopenharmony_ci lu->command_block_agent_address + SBP2_ORB_POINTER); 14868c2ecf20Sopenharmony_ci retval = 0; 14878c2ecf20Sopenharmony_ci out: 14888c2ecf20Sopenharmony_ci kref_put(&orb->base.kref, free_orb); 14898c2ecf20Sopenharmony_ci return retval; 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_cistatic int sbp2_scsi_slave_alloc(struct scsi_device *sdev) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu = sdev->hostdata; 14958c2ecf20Sopenharmony_ci 14968c2ecf20Sopenharmony_ci /* (Re-)Adding logical units via the SCSI stack is not supported. */ 14978c2ecf20Sopenharmony_ci if (!lu) 14988c2ecf20Sopenharmony_ci return -ENOSYS; 14998c2ecf20Sopenharmony_ci 15008c2ecf20Sopenharmony_ci sdev->allow_restart = 1; 15018c2ecf20Sopenharmony_ci 15028c2ecf20Sopenharmony_ci /* 15038c2ecf20Sopenharmony_ci * SBP-2 does not require any alignment, but we set it anyway 15048c2ecf20Sopenharmony_ci * for compatibility with earlier versions of this driver. 15058c2ecf20Sopenharmony_ci */ 15068c2ecf20Sopenharmony_ci blk_queue_update_dma_alignment(sdev->request_queue, 4 - 1); 15078c2ecf20Sopenharmony_ci 15088c2ecf20Sopenharmony_ci if (lu->tgt->workarounds & SBP2_WORKAROUND_INQUIRY_36) 15098c2ecf20Sopenharmony_ci sdev->inquiry_len = 36; 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_ci return 0; 15128c2ecf20Sopenharmony_ci} 15138c2ecf20Sopenharmony_ci 15148c2ecf20Sopenharmony_cistatic int sbp2_scsi_slave_configure(struct scsi_device *sdev) 15158c2ecf20Sopenharmony_ci{ 15168c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu = sdev->hostdata; 15178c2ecf20Sopenharmony_ci 15188c2ecf20Sopenharmony_ci sdev->use_10_for_rw = 1; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci if (sbp2_param_exclusive_login) 15218c2ecf20Sopenharmony_ci sdev->manage_start_stop = 1; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci if (sdev->type == TYPE_ROM) 15248c2ecf20Sopenharmony_ci sdev->use_10_for_ms = 1; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (sdev->type == TYPE_DISK && 15278c2ecf20Sopenharmony_ci lu->tgt->workarounds & SBP2_WORKAROUND_MODE_SENSE_8) 15288c2ecf20Sopenharmony_ci sdev->skip_ms_page_8 = 1; 15298c2ecf20Sopenharmony_ci 15308c2ecf20Sopenharmony_ci if (lu->tgt->workarounds & SBP2_WORKAROUND_FIX_CAPACITY) 15318c2ecf20Sopenharmony_ci sdev->fix_capacity = 1; 15328c2ecf20Sopenharmony_ci 15338c2ecf20Sopenharmony_ci if (lu->tgt->workarounds & SBP2_WORKAROUND_POWER_CONDITION) 15348c2ecf20Sopenharmony_ci sdev->start_stop_pwr_cond = 1; 15358c2ecf20Sopenharmony_ci 15368c2ecf20Sopenharmony_ci if (lu->tgt->workarounds & SBP2_WORKAROUND_128K_MAX_TRANS) 15378c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(sdev->request_queue, 128 * 1024 / 512); 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci return 0; 15408c2ecf20Sopenharmony_ci} 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci/* 15438c2ecf20Sopenharmony_ci * Called by scsi stack when something has really gone wrong. Usually 15448c2ecf20Sopenharmony_ci * called when a command has timed-out for some reason. 15458c2ecf20Sopenharmony_ci */ 15468c2ecf20Sopenharmony_cistatic int sbp2_scsi_abort(struct scsi_cmnd *cmd) 15478c2ecf20Sopenharmony_ci{ 15488c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu = cmd->device->hostdata; 15498c2ecf20Sopenharmony_ci 15508c2ecf20Sopenharmony_ci dev_notice(lu_dev(lu), "sbp2_scsi_abort\n"); 15518c2ecf20Sopenharmony_ci sbp2_agent_reset(lu); 15528c2ecf20Sopenharmony_ci sbp2_cancel_orbs(lu); 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci return SUCCESS; 15558c2ecf20Sopenharmony_ci} 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci/* 15588c2ecf20Sopenharmony_ci * Format of /sys/bus/scsi/devices/.../ieee1394_id: 15598c2ecf20Sopenharmony_ci * u64 EUI-64 : u24 directory_ID : u16 LUN (all printed in hexadecimal) 15608c2ecf20Sopenharmony_ci * 15618c2ecf20Sopenharmony_ci * This is the concatenation of target port identifier and logical unit 15628c2ecf20Sopenharmony_ci * identifier as per SAM-2...SAM-4 annex A. 15638c2ecf20Sopenharmony_ci */ 15648c2ecf20Sopenharmony_cistatic ssize_t sbp2_sysfs_ieee1394_id_show(struct device *dev, 15658c2ecf20Sopenharmony_ci struct device_attribute *attr, char *buf) 15668c2ecf20Sopenharmony_ci{ 15678c2ecf20Sopenharmony_ci struct scsi_device *sdev = to_scsi_device(dev); 15688c2ecf20Sopenharmony_ci struct sbp2_logical_unit *lu; 15698c2ecf20Sopenharmony_ci 15708c2ecf20Sopenharmony_ci if (!sdev) 15718c2ecf20Sopenharmony_ci return 0; 15728c2ecf20Sopenharmony_ci 15738c2ecf20Sopenharmony_ci lu = sdev->hostdata; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci return sprintf(buf, "%016llx:%06x:%04x\n", 15768c2ecf20Sopenharmony_ci (unsigned long long)lu->tgt->guid, 15778c2ecf20Sopenharmony_ci lu->tgt->directory_id, lu->lun); 15788c2ecf20Sopenharmony_ci} 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ieee1394_id, S_IRUGO, sbp2_sysfs_ieee1394_id_show, NULL); 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_cistatic struct device_attribute *sbp2_scsi_sysfs_attrs[] = { 15838c2ecf20Sopenharmony_ci &dev_attr_ieee1394_id, 15848c2ecf20Sopenharmony_ci NULL 15858c2ecf20Sopenharmony_ci}; 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic struct scsi_host_template scsi_driver_template = { 15888c2ecf20Sopenharmony_ci .module = THIS_MODULE, 15898c2ecf20Sopenharmony_ci .name = "SBP-2 IEEE-1394", 15908c2ecf20Sopenharmony_ci .proc_name = "sbp2", 15918c2ecf20Sopenharmony_ci .queuecommand = sbp2_scsi_queuecommand, 15928c2ecf20Sopenharmony_ci .slave_alloc = sbp2_scsi_slave_alloc, 15938c2ecf20Sopenharmony_ci .slave_configure = sbp2_scsi_slave_configure, 15948c2ecf20Sopenharmony_ci .eh_abort_handler = sbp2_scsi_abort, 15958c2ecf20Sopenharmony_ci .this_id = -1, 15968c2ecf20Sopenharmony_ci .sg_tablesize = SG_ALL, 15978c2ecf20Sopenharmony_ci .max_segment_size = SBP2_MAX_SEG_SIZE, 15988c2ecf20Sopenharmony_ci .can_queue = 1, 15998c2ecf20Sopenharmony_ci .sdev_attrs = sbp2_scsi_sysfs_attrs, 16008c2ecf20Sopenharmony_ci}; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ciMODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>"); 16038c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SCSI over IEEE1394"); 16048c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 16058c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci/* Provide a module alias so root-on-sbp2 initrds don't break. */ 16088c2ecf20Sopenharmony_ciMODULE_ALIAS("sbp2"); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_cistatic int __init sbp2_init(void) 16118c2ecf20Sopenharmony_ci{ 16128c2ecf20Sopenharmony_ci return driver_register(&sbp2_driver.driver); 16138c2ecf20Sopenharmony_ci} 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_cistatic void __exit sbp2_cleanup(void) 16168c2ecf20Sopenharmony_ci{ 16178c2ecf20Sopenharmony_ci driver_unregister(&sbp2_driver.driver); 16188c2ecf20Sopenharmony_ci} 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_cimodule_init(sbp2_init); 16218c2ecf20Sopenharmony_cimodule_exit(sbp2_cleanup); 1622