int blocked; /* ditto */
};
+static struct fw_device *target_device(struct sbp2_target *tgt)
+{
+ return fw_parent_device(tgt->unit);
+}
+
/* Impossible login_id, to detect logout attempt before successful login */
#define INVALID_LOGIN_ID 0x10000
-/*
- * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be
- * provided in the config rom. Most devices do provide a value, which
- * we'll use for login management orbs, but with some sane limits.
- */
-#define SBP2_MIN_LOGIN_ORB_TIMEOUT 5000U /* Timeout in ms */
-#define SBP2_MAX_LOGIN_ORB_TIMEOUT 40000U /* Timeout in ms */
-#define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */
+#define SBP2_ORB_TIMEOUT 2000U /* Timeout in ms */
#define SBP2_ORB_NULL 0x80000000
#define SBP2_RETRY_LIMIT 0xf /* 15 retries */
#define SBP2_CYCLE_LIMIT (0xc8 << 12) /* 200 125us cycles */
/*
+ * There is no transport protocol limit to the CDB length, but we implement
+ * a fixed length only. 16 bytes is enough for disks larger than 2 TB.
+ */
+#define SBP2_MAX_CDB_SIZE 16
+
+/*
* The default maximum s/g segment size of a FireWire controller is
* usually 0x10000, but SBP-2 only allows 0xffff. Since buffers have to
* be quadlet-aligned, we set the length limit to 0xffff & ~3.
struct sbp2_pointer next;
struct sbp2_pointer data_descriptor;
__be32 misc;
- u8 command_block[12];
+ u8 command_block[SBP2_MAX_CDB_SIZE];
} request;
struct scsi_cmnd *cmd;
scsi_done_fn_t done;
/* DViCO Momobay FX-3A with TSB42AA9A bridge */ {
.firmware_revision = 0x002800,
.model = 0x000000,
- .workarounds = SBP2_WORKAROUND_DELAY_INQUIRY |
- SBP2_WORKAROUND_POWER_CONDITION,
+ .workarounds = SBP2_WORKAROUND_POWER_CONDITION,
},
/* Initio bridges, actually only needed for some older ones */ {
.firmware_revision = 0x000200,
struct sbp2_logical_unit *lu = callback_data;
struct sbp2_orb *orb;
struct sbp2_status status;
- size_t header_size;
unsigned long flags;
if (tcode != TCODE_WRITE_BLOCK_REQUEST ||
- length == 0 || length > sizeof(status)) {
+ length < 8 || length > sizeof(status)) {
fw_send_response(card, request, RCODE_TYPE_ERROR);
return;
}
- header_size = min(length, 2 * sizeof(u32));
- fw_memcpy_from_be32(&status, payload, header_size);
- if (length > header_size)
- memcpy(status.data, payload + 8, length - header_size);
+ status.status = be32_to_cpup(payload);
+ status.orb_low = be32_to_cpup(payload + 4);
+ memset(status.data, 0, sizeof(status.data));
+ if (length > 8)
+ memcpy(status.data, payload + 8, length - 8);
+
if (STATUS_GET_SOURCE(status) == 2 || STATUS_GET_SOURCE(status) == 3) {
fw_notify("non-orb related status write, not handled\n");
fw_send_response(card, request, RCODE_COMPLETE);
}
spin_unlock_irqrestore(&card->lock, flags);
- if (&orb->link != &lu->orb_list)
+ if (&orb->link != &lu->orb_list) {
orb->callback(orb, &status);
- else
+ kref_put(&orb->kref, free_orb);
+ } else {
fw_error("status write for unknown orb\n");
-
- kref_put(&orb->kref, free_orb);
+ }
fw_send_response(card, request, RCODE_COMPLETE);
}
static void sbp2_send_orb(struct sbp2_orb *orb, struct sbp2_logical_unit *lu,
int node_id, int generation, u64 offset)
{
- struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ struct fw_device *device = target_device(lu->tgt);
unsigned long flags;
orb->pointer.high = 0;
static int sbp2_cancel_orbs(struct sbp2_logical_unit *lu)
{
- struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ struct fw_device *device = target_device(lu->tgt);
struct sbp2_orb *orb, *next;
struct list_head list;
unsigned long flags;
int generation, int function,
int lun_or_login_id, void *response)
{
- struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ struct fw_device *device = target_device(lu->tgt);
struct sbp2_management_orb *orb;
unsigned int timeout;
int retval = -ENOMEM;
static void sbp2_agent_reset(struct sbp2_logical_unit *lu)
{
- struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ struct fw_device *device = target_device(lu->tgt);
__be32 d = 0;
fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
static void sbp2_agent_reset_no_wait(struct sbp2_logical_unit *lu)
{
- struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ struct fw_device *device = target_device(lu->tgt);
struct fw_transaction *t;
static __be32 d;
static void sbp2_conditionally_block(struct sbp2_logical_unit *lu)
{
struct sbp2_target *tgt = lu->tgt;
- struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+ struct fw_card *card = target_device(tgt)->card;
struct Scsi_Host *shost =
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
unsigned long flags;
static void sbp2_conditionally_unblock(struct sbp2_logical_unit *lu)
{
struct sbp2_target *tgt = lu->tgt;
- struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+ struct fw_card *card = target_device(tgt)->card;
struct Scsi_Host *shost =
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
unsigned long flags;
*/
static void sbp2_unblock(struct sbp2_target *tgt)
{
- struct fw_card *card = fw_device(tgt->unit->device.parent)->card;
+ struct fw_card *card = target_device(tgt)->card;
struct Scsi_Host *shost =
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
unsigned long flags;
struct Scsi_Host *shost =
container_of((void *)tgt, struct Scsi_Host, hostdata[0]);
struct scsi_device *sdev;
- struct fw_device *device = fw_device(tgt->unit->device.parent);
+ struct fw_device *device = target_device(tgt);
/* prevent deadlocks */
sbp2_unblock(tgt);
fw_device_put(device);
}
-static struct workqueue_struct *sbp2_wq;
+static void sbp2_target_get(struct sbp2_target *tgt)
+{
+ kref_get(&tgt->kref);
+}
static void sbp2_target_put(struct sbp2_target *tgt)
{
kref_put(&tgt->kref, sbp2_release_target);
}
+static struct workqueue_struct *sbp2_wq;
+
/*
* Always get the target's kref when scheduling work on one its units.
* Each workqueue job is responsible to call sbp2_target_put() upon return.
*/
static void sbp2_queue_work(struct sbp2_logical_unit *lu, unsigned long delay)
{
- kref_get(&lu->tgt->kref);
+ sbp2_target_get(lu->tgt);
if (!queue_delayed_work(sbp2_wq, &lu->work, delay))
sbp2_target_put(lu->tgt);
}
*/
static void sbp2_set_busy_timeout(struct sbp2_logical_unit *lu)
{
- struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ struct fw_device *device = target_device(lu->tgt);
__be32 d = cpu_to_be32(SBP2_CYCLE_LIMIT | SBP2_RETRY_LIMIT);
fw_run_transaction(device->card, TCODE_WRITE_QUADLET_REQUEST,
struct sbp2_logical_unit *lu =
container_of(work, struct sbp2_logical_unit, work.work);
struct sbp2_target *tgt = lu->tgt;
- struct fw_device *device = fw_device(tgt->unit->device.parent);
+ struct fw_device *device = target_device(tgt);
struct Scsi_Host *shost;
struct scsi_device *sdev;
struct sbp2_login_response response;
{
struct fw_csr_iterator ci;
int key, value;
- unsigned int timeout;
fw_csr_iterator_init(&ci, directory);
while (fw_csr_iterator_next(&ci, &key, &value)) {
case SBP2_CSR_UNIT_CHARACTERISTICS:
/* the timeout value is stored in 500ms units */
- timeout = ((unsigned int) value >> 8 & 0xff) * 500;
- timeout = max(timeout, SBP2_MIN_LOGIN_ORB_TIMEOUT);
- tgt->mgt_orb_timeout =
- min(timeout, SBP2_MAX_LOGIN_ORB_TIMEOUT);
-
- if (timeout > tgt->mgt_orb_timeout)
- fw_notify("%s: config rom contains %ds "
- "management ORB timeout, limiting "
- "to %ds\n", tgt->bus_id,
- timeout / 1000,
- tgt->mgt_orb_timeout / 1000);
+ tgt->mgt_orb_timeout = (value >> 8 & 0xff) * 500;
break;
case SBP2_CSR_LOGICAL_UNIT_NUMBER:
return 0;
}
+/*
+ * Per section 7.4.8 of the SBP-2 spec, a mgt_ORB_timeout value can be
+ * provided in the config rom. Most devices do provide a value, which
+ * we'll use for login management orbs, but with some sane limits.
+ */
+static void sbp2_clamp_management_orb_timeout(struct sbp2_target *tgt)
+{
+ unsigned int timeout = tgt->mgt_orb_timeout;
+
+ if (timeout > 40000)
+ fw_notify("%s: %ds mgt_ORB_timeout limited to 40s\n",
+ tgt->bus_id, timeout / 1000);
+
+ tgt->mgt_orb_timeout = clamp_val(timeout, 5000, 40000);
+}
+
static void sbp2_init_workarounds(struct sbp2_target *tgt, u32 model,
u32 firmware_revision)
{
static int sbp2_probe(struct device *dev)
{
struct fw_unit *unit = fw_unit(dev);
- struct fw_device *device = fw_device(unit->device.parent);
+ struct fw_device *device = fw_parent_device(unit);
struct sbp2_target *tgt;
struct sbp2_logical_unit *lu;
struct Scsi_Host *shost;
return -ENOMEM;
tgt = (struct sbp2_target *)shost->hostdata;
- unit->device.driver_data = tgt;
+ dev_set_drvdata(&unit->device, tgt);
tgt->unit = unit;
kref_init(&tgt->kref);
INIT_LIST_HEAD(&tgt->lu_list);
if (fw_device_enable_phys_dma(device) < 0)
goto fail_shost_put;
+ shost->max_cmd_len = SBP2_MAX_CDB_SIZE;
+
if (scsi_add_host(shost, &unit->device) < 0)
goto fail_shost_put;
&firmware_revision) < 0)
goto fail_tgt_put;
+ sbp2_clamp_management_orb_timeout(tgt);
sbp2_init_workarounds(tgt, model, firmware_revision);
/*
static int sbp2_remove(struct device *dev)
{
struct fw_unit *unit = fw_unit(dev);
- struct sbp2_target *tgt = unit->device.driver_data;
+ struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
sbp2_target_put(tgt);
return 0;
struct sbp2_logical_unit *lu =
container_of(work, struct sbp2_logical_unit, work.work);
struct sbp2_target *tgt = lu->tgt;
- struct fw_device *device = fw_device(tgt->unit->device.parent);
+ struct fw_device *device = target_device(tgt);
int generation, node_id, local_node_id;
if (fw_device_is_shutdown(device))
static void sbp2_update(struct fw_unit *unit)
{
- struct sbp2_target *tgt = unit->device.driver_data;
+ struct sbp2_target *tgt = dev_get_drvdata(&unit->device);
struct sbp2_logical_unit *lu;
- fw_device_enable_phys_dma(fw_device(unit->device.parent));
+ fw_device_enable_phys_dma(fw_parent_device(unit));
/*
* Fw-core serializes sbp2_update() against sbp2_remove().
{
struct sbp2_command_orb *orb =
container_of(base_orb, struct sbp2_command_orb, base);
- struct fw_device *device = fw_device(orb->lu->tgt->unit->device.parent);
+ struct fw_device *device = target_device(orb->lu->tgt);
int result;
if (status != NULL) {
static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
{
struct sbp2_logical_unit *lu = cmd->device->hostdata;
- struct fw_device *device = fw_device(lu->tgt->unit->device.parent);
+ struct fw_device *device = target_device(lu->tgt);
struct sbp2_command_orb *orb;
int generation, retval = SCSI_MLQUEUE_HOST_BUSY;