Commit c275257c authored by Ben Collins's avatar Ben Collins

[PATCH] IEEE-1394/Firewire updates

- Add driver registration for dv1394/video1394/raw1394.
- Fix 3 sleep-while-atomic bugs in ohci1394 and ieee1394.
- Cleanup some bus-reset handling in ohci1394.
- Add empty config-rom handling.
- Check and handle SBP-2 logins active/available for non-exclusive
  logins.
- Fix bug in SBP-2 DMA cleanup.
parent 48b2bd92
...@@ -116,6 +116,7 @@ ...@@ -116,6 +116,7 @@
#include "ieee1394.h" #include "ieee1394.h"
#include "ieee1394_types.h" #include "ieee1394_types.h"
#include "ieee1394_hotplug.h"
#include "hosts.h" #include "hosts.h"
#include "ieee1394_core.h" #include "ieee1394_core.h"
#include "highlevel.h" #include "highlevel.h"
...@@ -140,7 +141,7 @@ ...@@ -140,7 +141,7 @@
(will cause undeflows if your machine is too slow!) (will cause undeflows if your machine is too slow!)
*/ */
#define DV1394_DEBUG_LEVEL 1 #define DV1394_DEBUG_LEVEL 0
/* for debugging use ONLY: allow more than one open() of the device */ /* for debugging use ONLY: allow more than one open() of the device */
/* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */ /* #define DV1394_ALLOW_MORE_THAN_ONE_OPEN 1 */
...@@ -2469,6 +2470,32 @@ static int dv1394_devfs_add_entry(struct video_card *video) ...@@ -2469,6 +2470,32 @@ static int dv1394_devfs_add_entry(struct video_card *video)
} }
#endif /* CONFIG_DEVFS_FS */ #endif /* CONFIG_DEVFS_FS */
/*** HOTPLUG STUFF **********************************************************/
/*
* Export information about protocols/devices supported by this driver.
*/
static struct ieee1394_device_id dv1394_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
.version = AVC_SW_VERSION_ENTRY & 0xffffff
},
{ }
};
MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table);
static struct hpsb_protocol_driver dv1394_driver = {
.name = "DV/1394 Driver",
.id_table = dv1394_id_table,
.driver = {
.name = "dv1394",
.bus = &ieee1394_bus_type,
},
};
/*** IEEE1394 HPSB CALLBACKS ***********************************************/ /*** IEEE1394 HPSB CALLBACKS ***********************************************/
static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode) static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes mode)
...@@ -2897,6 +2924,8 @@ static void __exit dv1394_exit_module(void) ...@@ -2897,6 +2924,8 @@ static void __exit dv1394_exit_module(void)
printk(KERN_ERR "dv1394: Error unregistering ioctl32 translations\n"); printk(KERN_ERR "dv1394: Error unregistering ioctl32 translations\n");
#endif #endif
hpsb_unregister_protocol(&dv1394_driver);
hpsb_unregister_highlevel (hl_handle); hpsb_unregister_highlevel (hl_handle);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
#ifdef CONFIG_DEVFS_FS #ifdef CONFIG_DEVFS_FS
...@@ -2947,6 +2976,8 @@ static int __init dv1394_init_module(void) ...@@ -2947,6 +2976,8 @@ static int __init dv1394_init_module(void)
return -ENOMEM; return -ENOMEM;
} }
hpsb_register_protocol(&dv1394_driver);
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
/* First compatible ones */ /* First compatible ones */
ret = register_ioctl32_conversion(DV1394_IOC_SHUTDOWN, NULL); ret = register_ioctl32_conversion(DV1394_IOC_SHUTDOWN, NULL);
......
...@@ -164,7 +164,7 @@ void hpsb_add_host(struct hpsb_host *host) ...@@ -164,7 +164,7 @@ void hpsb_add_host(struct hpsb_host *host)
spin_unlock_irqrestore(&hosts_lock, flags); spin_unlock_irqrestore(&hosts_lock, flags);
highlevel_add_host(host); highlevel_add_host(host);
host->driver->devctl(host, RESET_BUS, 0); host->driver->devctl(host, RESET_BUS, LONG_RESET);
} }
void hpsb_remove_host(struct hpsb_host *host) void hpsb_remove_host(struct hpsb_host *host)
......
...@@ -11,6 +11,14 @@ ...@@ -11,6 +11,14 @@
#define IEEE1394_MATCH_SPECIFIER_ID 0x0004 #define IEEE1394_MATCH_SPECIFIER_ID 0x0004
#define IEEE1394_MATCH_VERSION 0x0008 #define IEEE1394_MATCH_VERSION 0x0008
/*
* Unit spec id and sw version entry for some protocols
*/
#define AVC_UNIT_SPEC_ID_ENTRY 0x0000A02D
#define AVC_SW_VERSION_ENTRY 0x00010001
#define CAMERA_UNIT_SPEC_ID_ENTRY 0x0000A02D
#define CAMERA_SW_VERSION_ENTRY 0x00000100
struct ieee1394_device_id { struct ieee1394_device_id {
u32 match_flags; u32 match_flags;
u32 vendor_id; u32 vendor_id;
......
...@@ -620,6 +620,10 @@ static struct node_entry *nodemgr_scan_root_directory ...@@ -620,6 +620,10 @@ static struct node_entry *nodemgr_scan_root_directory
if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
return NULL; return NULL;
if (CONFIG_ROM_BUS_INFO_LENGTH(quad) == 1) /* minimal config rom */
return NULL;
address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4; address += 4 + CONFIG_ROM_BUS_INFO_LENGTH(quad) * 4;
if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad)) if (nodemgr_read_quadlet(host, nodeid, generation, address, &quad))
...@@ -1332,6 +1336,13 @@ static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned ...@@ -1332,6 +1336,13 @@ static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned
header_size = buffer[0] >> 24; header_size = buffer[0] >> 24;
addr += 4; addr += 4;
if (header_size == 1) {
HPSB_INFO("Node " NODE_BUS_FMT " has a minimal ROM. "
"Vendor is %08x",
NODE_BUS_ARGS(nodeid), buffer[0] & 0x00ffffff);
return -1;
}
if (header_size < 4) { if (header_size < 4) {
HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM " HPSB_INFO("Node " NODE_BUS_FMT " has non-standard ROM "
"format (%d quads), cannot parse", "format (%d quads), cannot parse",
...@@ -1767,6 +1778,7 @@ static void nodemgr_remove_host(struct hpsb_host *host) ...@@ -1767,6 +1778,7 @@ static void nodemgr_remove_host(struct hpsb_host *host)
break; break;
} }
} }
spin_unlock_irqrestore (&host_info_lock, flags);
if (hi) { if (hi) {
if (hi->pid >= 0) { if (hi->pid >= 0) {
...@@ -1780,8 +1792,6 @@ static void nodemgr_remove_host(struct hpsb_host *host) ...@@ -1780,8 +1792,6 @@ static void nodemgr_remove_host(struct hpsb_host *host)
HPSB_ERR("NodeMgr: host %s does not exist, cannot remove", HPSB_ERR("NodeMgr: host %s does not exist, cannot remove",
host->driver->name); host->driver->name);
spin_unlock_irqrestore (&host_info_lock, flags);
return; return;
} }
......
...@@ -995,8 +995,24 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) ...@@ -995,8 +995,24 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
return -EFAULT; return -EFAULT;
} }
/* activate the legacy IR context */
if (ohci->ir_legacy_context.ohci == NULL) {
if (alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
DMA_CTX_ISO, 0, IR_NUM_DESC,
IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
OHCI1394_IsoRcvContextBase) < 0) {
PRINT(KERN_ERR, ohci->id, "%s: failed to allocate an IR context",
__FUNCTION__);
return -ENOMEM;
}
ohci->ir_legacy_channels = 0;
initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
DBGMSG(ohci->id, "ISO receive legacy context activated");
}
mask = (u64)0x1<<arg; mask = (u64)0x1<<arg;
spin_lock_irqsave(&ohci->IR_channel_lock, flags); spin_lock_irqsave(&ohci->IR_channel_lock, flags);
if (ohci->ISO_channel_usage & mask) { if (ohci->ISO_channel_usage & mask) {
...@@ -1007,23 +1023,6 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg) ...@@ -1007,23 +1023,6 @@ static int ohci_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
return -EFAULT; return -EFAULT;
} }
/* activate the legacy IR context */
if(ohci->ir_legacy_context.ohci == NULL) {
if(alloc_dma_rcv_ctx(ohci, &ohci->ir_legacy_context,
DMA_CTX_ISO, 0, IR_NUM_DESC,
IR_BUF_SIZE, IR_SPLIT_BUF_SIZE,
OHCI1394_IsoRcvContextBase) < 0) {
PRINT(KERN_ERR, ohci->id,
"%s: failed to allocate an IR context",
__FUNCTION__);
return -ENOMEM;
}
ohci->ir_legacy_channels = 0;
initialize_dma_rcv_ctx(&ohci->ir_legacy_context, 1);
DBGMSG(ohci->id, "ISO receive legacy context activated");
}
ohci->ISO_channel_usage |= mask; ohci->ISO_channel_usage |= mask;
ohci->ir_legacy_channels |= mask; ohci->ir_legacy_channels |= mask;
...@@ -2318,7 +2317,7 @@ static void ohci_irq_handler(int irq, void *dev_id, ...@@ -2318,7 +2317,7 @@ static void ohci_irq_handler(int irq, void *dev_id,
* or out manually into a port! The forced reset seems * or out manually into a port! The forced reset seems
* to solve this problem. This mainly effects nForce2. */ * to solve this problem. This mainly effects nForce2. */
if (loop_count > 10000) { if (loop_count > 10000) {
hpsb_reset_bus(host, 1); ohci_devctl(host, RESET_BUS, LONG_RESET);
DBGMSG(ohci->id, "Detected bus-reset loop. Forced a bus reset!"); DBGMSG(ohci->id, "Detected bus-reset loop. Forced a bus reset!");
loop_count = 0; loop_count = 0;
} }
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "highlevel.h" #include "highlevel.h"
#include "iso.h" #include "iso.h"
#include "ieee1394_transactions.h" #include "ieee1394_transactions.h"
#include "ieee1394_hotplug.h"
#include "raw1394.h" #include "raw1394.h"
#include "raw1394-private.h" #include "raw1394-private.h"
...@@ -2474,6 +2475,40 @@ static int raw1394_release(struct inode *inode, struct file *file) ...@@ -2474,6 +2475,40 @@ static int raw1394_release(struct inode *inode, struct file *file)
return 0; return 0;
} }
/*** HOTPLUG STUFF **********************************************************/
/*
* Export information about protocols/devices supported by this driver.
*/
static struct ieee1394_device_id raw1394_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
.specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff,
.version = AVC_SW_VERSION_ENTRY & 0xffffff
},
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
.specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
.version = CAMERA_SW_VERSION_ENTRY & 0xffffff
},
{ }
};
MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table);
static struct hpsb_protocol_driver raw1394_driver = {
.name = "raw1394 Driver",
.id_table = raw1394_id_table,
.driver = {
.name = "raw1394",
.bus = &ieee1394_bus_type,
},
};
/******************************************************************************/
static struct hpsb_highlevel_ops hl_ops = { static struct hpsb_highlevel_ops hl_ops = {
.add_host = add_host, .add_host = add_host,
.remove_host = remove_host, .remove_host = remove_host,
...@@ -2515,12 +2550,17 @@ static int __init init_raw1394(void) ...@@ -2515,12 +2550,17 @@ static int __init init_raw1394(void)
hpsb_unregister_highlevel(hl_handle); hpsb_unregister_highlevel(hl_handle);
return -EBUSY; return -EBUSY;
} }
printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME); printk(KERN_INFO "raw1394: /dev/%s device initialized\n", RAW1394_DEVICE_NAME);
hpsb_register_protocol(&raw1394_driver);
return 0; return 0;
} }
static void __exit cleanup_raw1394(void) static void __exit cleanup_raw1394(void)
{ {
hpsb_unregister_protocol(&raw1394_driver);
ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394); ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_RAW1394);
devfs_unregister(devfs_handle); devfs_unregister(devfs_handle);
hpsb_unregister_highlevel(hl_handle); hpsb_unregister_highlevel(hl_handle);
......
...@@ -641,7 +641,7 @@ static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_i ...@@ -641,7 +641,7 @@ static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_i
spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags); spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
for (i = 0; i < orbs; i++) { for (i = 0; i < orbs; i++) {
command = (struct sbp2_command_info *) command = (struct sbp2_command_info *)
kmalloc(sizeof(struct sbp2_command_info), GFP_KERNEL); kmalloc(sizeof(struct sbp2_command_info), GFP_ATOMIC);
if (!command) { if (!command) {
spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags); spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return(-ENOMEM); return(-ENOMEM);
...@@ -1049,6 +1049,22 @@ static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_director ...@@ -1049,6 +1049,22 @@ static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_director
goto alloc_fail; goto alloc_fail;
SBP2_DMA_ALLOC("consistent DMA region for login FIFO"); SBP2_DMA_ALLOC("consistent DMA region for login FIFO");
/* Query logins ORB DMA */
scsi_id->query_logins_orb =
pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_orb),
&scsi_id->query_logins_orb_dma);
if (!scsi_id->query_logins_orb)
goto alloc_fail;
SBP2_DMA_ALLOC("consistent DMA region for query logins ORB");
/* Query logins response DMA */
scsi_id->query_logins_response =
pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_response),
&scsi_id->query_logins_response_dma);
if (!scsi_id->query_logins_response)
goto alloc_fail;
SBP2_DMA_ALLOC("consistent DMA region for query logins response");
/* Reconnect ORB DMA */ /* Reconnect ORB DMA */
scsi_id->reconnect_orb = scsi_id->reconnect_orb =
pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb), pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb),
...@@ -1071,6 +1087,22 @@ static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_director ...@@ -1071,6 +1087,22 @@ static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_director
&scsi_id->login_orb_dma); &scsi_id->login_orb_dma);
if (!scsi_id->login_orb) { if (!scsi_id->login_orb) {
alloc_fail: alloc_fail:
if (scsi_id->query_logins_response) {
pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_query_logins_response),
scsi_id->query_logins_response,
scsi_id->query_logins_response_dma);
SBP2_DMA_FREE("query logins response DMA");
}
if (scsi_id->query_logins_orb) {
pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_query_logins_orb),
scsi_id->query_logins_orb,
scsi_id->query_logins_orb_dma);
SBP2_DMA_FREE("query logins ORB DMA");
}
if (scsi_id->logout_orb) { if (scsi_id->logout_orb) {
pci_free_consistent(hi->host->pdev, pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_logout_orb), sizeof(struct sbp2_logout_orb),
...@@ -1241,10 +1273,26 @@ static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id) ...@@ -1241,10 +1273,26 @@ static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
pci_free_consistent(hi->host->pdev, pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_logout_orb), sizeof(struct sbp2_logout_orb),
scsi_id->logout_orb, scsi_id->logout_orb,
scsi_id->reconnect_orb_dma); scsi_id->logout_orb_dma);
SBP2_DMA_FREE("single logout orb"); SBP2_DMA_FREE("single logout orb");
} }
if (scsi_id->query_logins_orb) {
pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_query_logins_orb),
scsi_id->query_logins_orb,
scsi_id->query_logins_orb_dma);
SBP2_DMA_FREE("single query logins orb");
}
if (scsi_id->query_logins_response) {
pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_query_logins_response),
scsi_id->query_logins_response,
scsi_id->query_logins_response_dma);
SBP2_DMA_FREE("single query logins data");
}
SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id); SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id);
kfree(scsi_id); kfree(scsi_id);
...@@ -1299,6 +1347,103 @@ static __inline__ int sbp2_command_conversion_device_type(u8 device_type) ...@@ -1299,6 +1347,103 @@ static __inline__ int sbp2_command_conversion_device_type(u8 device_type)
(device_type == TYPE_ROM)) ? 1:0); (device_type == TYPE_ROM)) ? 1:0);
} }
/*
* This function queries the device for the maximum concurrent logins it
* supports.
*/
static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
{
struct sbp2scsi_host_info *hi = scsi_id->hi;
quadlet_t data[2];
int max_logins;
int active_logins;
SBP2_DEBUG("sbp2_query_logins");
scsi_id->query_logins_orb->reserved1 = 0x0;
scsi_id->query_logins_orb->reserved2 = 0x0;
scsi_id->query_logins_orb->query_response_lo = scsi_id->query_logins_response_dma;
scsi_id->query_logins_orb->query_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
SBP2_DEBUG("sbp2_query_logins: query_response_hi/lo initialized");
scsi_id->query_logins_orb->lun_misc = ORB_SET_FUNCTION(QUERY_LOGINS_REQUEST);
scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
}
SBP2_DEBUG("sbp2_query_logins: lun_misc initialized");
scsi_id->query_logins_orb->reserved_resp_length =
ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response));
SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized");
scsi_id->query_logins_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +
SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
scsi_id->query_logins_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
SBP2_STATUS_FIFO_ADDRESS_HI);
SBP2_DEBUG("sbp2_query_logins: status FIFO initialized");
sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb));
SBP2_DEBUG("sbp2_query_logins: orb byte-swapped");
sbp2util_packet_dump(scsi_id->query_logins_orb, sizeof(stuct sbp2_query_logins_orb),
"sbp2 query logins orb", scsi_id->query_logins_orb_dma);
memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
SBP2_DEBUG("sbp2_query_logins: query_logins_response/status FIFO memset");
data[0] = ORB_SET_NODE_ID(hi->host->node_id);
data[1] = scsi_id->query_logins_orb_dma;
sbp2util_cpu_to_be32_buffer(data, 8);
atomic_set(&scsi_id->sbp2_login_complete, 0);
SBP2_DEBUG("sbp2_query_logins: prepared to write");
hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
SBP2_DEBUG("sbp2_query_logins: written");
if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
SBP2_ERR("Error querying logins to SBP-2 device - timed out");
return(-EIO);
}
if (scsi_id->status_block.ORB_offset_lo != scsi_id->query_logins_orb_dma) {
SBP2_ERR("Error querying logins to SBP-2 device - timed out");
return(-EIO);
}
if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
SBP2_ERR("Error querying logins to SBP-2 device - timed out");
return(-EIO);
}
sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_response, sizeof(struct sbp2_query_logins_response));
SBP2_DEBUG("length_max_logins = %x",
(unsigned int)scsi_id->query_logins_response->length_max_logins);
SBP2_INFO("Query logins to SBP-2 device successful");
max_logins = RESPONSE_GET_MAX_LOGINS(scsi_id->query_logins_response->length_max_logins);
SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);
active_logins = RESPONSE_GET_ACTIVE_LOGINS(scsi_id->query_logins_response->length_max_logins);
SBP2_INFO("Number of active logins: %d", active_logins);
if (active_logins >= max_logins) {
return(-EIO);
}
return 0;
}
/* /*
* This function is called in order to login to a particular SBP-2 device, * This function is called in order to login to a particular SBP-2 device,
* after a bus reset. * after a bus reset.
...@@ -1315,6 +1460,13 @@ static int sbp2_login_device(struct scsi_id_instance_data *scsi_id) ...@@ -1315,6 +1460,13 @@ static int sbp2_login_device(struct scsi_id_instance_data *scsi_id)
return(-EIO); return(-EIO);
} }
if (!exclusive_login) {
if (sbp2_query_logins(scsi_id)) {
SBP2_ERR("Device does not support any more concurrent logins");
return(-EIO);
}
}
/* Set-up login ORB, assume no password */ /* Set-up login ORB, assume no password */
scsi_id->login_orb->password_hi = 0; scsi_id->login_orb->password_hi = 0;
scsi_id->login_orb->password_lo = 0; scsi_id->login_orb->password_lo = 0;
...@@ -2563,6 +2715,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest ...@@ -2563,6 +2715,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
* It's probably a login/logout/reconnect status. * It's probably a login/logout/reconnect status.
*/ */
if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) || if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
(scsi_id->query_logins_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
(scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) || (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
(scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) { (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) {
atomic_set(&scsi_id->sbp2_login_complete, 1); atomic_set(&scsi_id->sbp2_login_complete, 1);
......
...@@ -93,6 +93,29 @@ struct sbp2_login_response { ...@@ -93,6 +93,29 @@ struct sbp2_login_response {
#define ORB_SET_LOGIN_ID(value) (value & 0xffff) #define ORB_SET_LOGIN_ID(value) (value & 0xffff)
#define ORB_SET_QUERY_LOGINS_RESP_LENGTH(value) (value & 0xffff)
struct sbp2_query_logins_orb {
u32 reserved1;
u32 reserved2;
u32 query_response_hi;
u32 query_response_lo;
u32 lun_misc;
u32 reserved_resp_length;
u32 status_FIFO_hi;
u32 status_FIFO_lo;
};
#define RESPONSE_GET_MAX_LOGINS(value) (value & 0xffff)
#define RESPONSE_GET_ACTIVE_LOGINS(value) ((RESPONSE_GET_LENGTH(value) - 4) / 12)
struct sbp2_query_logins_response {
u32 length_max_logins;
u32 misc_IDs;
u32 initiator_misc_hi;
u32 initiator_misc_lo;
};
struct sbp2_reconnect_orb { struct sbp2_reconnect_orb {
u32 reserved1; u32 reserved1;
u32 reserved2; u32 reserved2;
...@@ -340,6 +363,10 @@ struct scsi_id_instance_data { ...@@ -340,6 +363,10 @@ struct scsi_id_instance_data {
dma_addr_t login_orb_dma; dma_addr_t login_orb_dma;
struct sbp2_login_response *login_response; struct sbp2_login_response *login_response;
dma_addr_t login_response_dma; dma_addr_t login_response_dma;
struct sbp2_query_logins_orb *query_logins_orb;
dma_addr_t query_logins_orb_dma;
struct sbp2_query_logins_response *query_logins_response;
dma_addr_t query_logins_response_dma;
struct sbp2_reconnect_orb *reconnect_orb; struct sbp2_reconnect_orb *reconnect_orb;
dma_addr_t reconnect_orb_dma; dma_addr_t reconnect_orb_dma;
struct sbp2_logout_orb *logout_orb; struct sbp2_logout_orb *logout_orb;
...@@ -365,7 +392,7 @@ struct scsi_id_instance_data { ...@@ -365,7 +392,7 @@ struct scsi_id_instance_data {
u32 sbp2_firmware_revision; u32 sbp2_firmware_revision;
/* /*
* Variable used for logins, reconnects, logouts * Variable used for logins, reconnects, logouts, query logins
*/ */
atomic_t sbp2_login_complete; atomic_t sbp2_login_complete;
...@@ -457,6 +484,7 @@ static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_ ...@@ -457,6 +484,7 @@ static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_
/* /*
* SBP-2 protocol related prototypes * SBP-2 protocol related prototypes
*/ */
static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id);
static int sbp2_login_device(struct scsi_id_instance_data *scsi_id); static int sbp2_login_device(struct scsi_id_instance_data *scsi_id);
static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id); static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id);
static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id); static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id);
......
...@@ -48,6 +48,7 @@ ...@@ -48,6 +48,7 @@
#include "ieee1394.h" #include "ieee1394.h"
#include "ieee1394_types.h" #include "ieee1394_types.h"
#include "ieee1394_hotplug.h"
#include "hosts.h" #include "hosts.h"
#include "ieee1394_core.h" #include "ieee1394_core.h"
#include "highlevel.h" #include "highlevel.h"
...@@ -1247,6 +1248,31 @@ static struct file_operations video1394_fops= ...@@ -1247,6 +1248,31 @@ static struct file_operations video1394_fops=
.release = video1394_release .release = video1394_release
}; };
/*** HOTPLUG STUFF **********************************************************/
/*
* Export information about protocols/devices supported by this driver.
*/
static struct ieee1394_device_id video1394_id_table[] = {
{
.match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION,
.specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff,
.version = CAMERA_SW_VERSION_ENTRY & 0xffffff
},
{ }
};
MODULE_DEVICE_TABLE(ieee1394, video1394_id_table);
static struct hpsb_protocol_driver video1394_driver = {
.name = "1394 Digital Camera Driver",
.id_table = video1394_id_table,
.driver = {
.name = VIDEO1394_DRIVER_NAME,
.bus = &ieee1394_bus_type,
},
};
static int video1394_init(struct ti_ohci *ohci) static int video1394_init(struct ti_ohci *ohci)
{ {
struct video_card *video; struct video_card *video;
...@@ -1467,6 +1493,8 @@ static void __exit video1394_exit_module (void) ...@@ -1467,6 +1493,8 @@ static void __exit video1394_exit_module (void)
PRINT_G(KERN_INFO, "Error unregistering ioctl32 translations"); PRINT_G(KERN_INFO, "Error unregistering ioctl32 translations");
#endif #endif
hpsb_unregister_protocol(&video1394_driver);
hpsb_unregister_highlevel (hl_handle); hpsb_unregister_highlevel (hl_handle);
devfs_unregister(devfs_handle); devfs_unregister(devfs_handle);
...@@ -1496,6 +1524,8 @@ static int __init video1394_init_module (void) ...@@ -1496,6 +1524,8 @@ static int __init video1394_init_module (void)
return -ENOMEM; return -ENOMEM;
} }
hpsb_register_protocol(&video1394_driver);
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
/* First the compatible ones */ /* First the compatible ones */
ret = register_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL, NULL); ret = register_ioctl32_conversion(VIDEO1394_IOC_LISTEN_CHANNEL, NULL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment