firewire: Allocate scsi_host up front and allocate the sbp2_device as hostdata.
Avoids an extra allocation and simplifies lifetime rules for the scsi_host. Signed-off-by: Kristian Hoegsberg <krh@redhat.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
This commit is contained in:
parent
1e4c7b0dab
commit
ad85274fb7
1 changed files with 50 additions and 84 deletions
|
@ -74,7 +74,6 @@ struct sbp2_device {
|
||||||
|
|
||||||
int retries;
|
int retries;
|
||||||
struct delayed_work work;
|
struct delayed_work work;
|
||||||
struct Scsi_Host *scsi_host;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
|
#define SBP2_MAX_SG_ELEMENT_LENGTH 0xf000
|
||||||
|
@ -519,30 +518,32 @@ static int sbp2_agent_reset(struct fw_unit *unit)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_scsi_devices(struct fw_unit *unit);
|
|
||||||
static void remove_scsi_devices(struct fw_unit *unit);
|
|
||||||
static void sbp2_reconnect(struct work_struct *work);
|
static void sbp2_reconnect(struct work_struct *work);
|
||||||
|
static struct scsi_host_template scsi_driver_template;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
release_sbp2_device(struct kref *kref)
|
release_sbp2_device(struct kref *kref)
|
||||||
{
|
{
|
||||||
struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref);
|
struct sbp2_device *sd = container_of(kref, struct sbp2_device, kref);
|
||||||
|
struct Scsi_Host *host =
|
||||||
|
container_of((void *)sd, struct Scsi_Host, hostdata[0]);
|
||||||
|
|
||||||
sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation,
|
sbp2_send_management_orb(sd->unit, sd->node_id, sd->generation,
|
||||||
SBP2_LOGOUT_REQUEST, sd->login_id, NULL);
|
SBP2_LOGOUT_REQUEST, sd->login_id, NULL);
|
||||||
|
|
||||||
remove_scsi_devices(sd->unit);
|
scsi_remove_host(host);
|
||||||
|
|
||||||
fw_core_remove_address_handler(&sd->address_handler);
|
fw_core_remove_address_handler(&sd->address_handler);
|
||||||
fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id);
|
fw_notify("removed sbp2 unit %s\n", sd->unit->device.bus_id);
|
||||||
put_device(&sd->unit->device);
|
put_device(&sd->unit->device);
|
||||||
kfree(sd);
|
scsi_host_put(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sbp2_login(struct work_struct *work)
|
static void sbp2_login(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct sbp2_device *sd =
|
struct sbp2_device *sd =
|
||||||
container_of(work, struct sbp2_device, work.work);
|
container_of(work, struct sbp2_device, work.work);
|
||||||
|
struct Scsi_Host *host =
|
||||||
|
container_of((void *)sd, struct Scsi_Host, hostdata[0]);
|
||||||
struct fw_unit *unit = sd->unit;
|
struct fw_unit *unit = sd->unit;
|
||||||
struct fw_device *device = fw_device(unit->device.parent);
|
struct fw_device *device = fw_device(unit->device.parent);
|
||||||
struct sbp2_login_response response;
|
struct sbp2_login_response response;
|
||||||
|
@ -562,7 +563,6 @@ static void sbp2_login(struct work_struct *work)
|
||||||
} else {
|
} else {
|
||||||
fw_error("failed to login to %s\n",
|
fw_error("failed to login to %s\n",
|
||||||
unit->device.bus_id);
|
unit->device.bus_id);
|
||||||
remove_scsi_devices(unit);
|
|
||||||
kref_put(&sd->kref, release_sbp2_device);
|
kref_put(&sd->kref, release_sbp2_device);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
@ -595,7 +595,9 @@ static void sbp2_login(struct work_struct *work)
|
||||||
PREPARE_DELAYED_WORK(&sd->work, sbp2_reconnect);
|
PREPARE_DELAYED_WORK(&sd->work, sbp2_reconnect);
|
||||||
sbp2_agent_reset(unit);
|
sbp2_agent_reset(unit);
|
||||||
|
|
||||||
retval = add_scsi_devices(unit);
|
/* FIXME: Loop over luns here. */
|
||||||
|
lun = 0;
|
||||||
|
retval = scsi_add_device(host, 0, 0, lun);
|
||||||
if (retval < 0) {
|
if (retval < 0) {
|
||||||
sbp2_send_management_orb(unit, sd->node_id, sd->generation,
|
sbp2_send_management_orb(unit, sd->node_id, sd->generation,
|
||||||
SBP2_LOGOUT_REQUEST, sd->login_id,
|
SBP2_LOGOUT_REQUEST, sd->login_id,
|
||||||
|
@ -615,13 +617,16 @@ static int sbp2_probe(struct device *dev)
|
||||||
struct fw_device *device = fw_device(unit->device.parent);
|
struct fw_device *device = fw_device(unit->device.parent);
|
||||||
struct sbp2_device *sd;
|
struct sbp2_device *sd;
|
||||||
struct fw_csr_iterator ci;
|
struct fw_csr_iterator ci;
|
||||||
int i, key, value;
|
struct Scsi_Host *host;
|
||||||
|
int i, key, value, err;
|
||||||
u32 model, firmware_revision;
|
u32 model, firmware_revision;
|
||||||
|
|
||||||
sd = kzalloc(sizeof *sd, GFP_KERNEL);
|
err = -ENOMEM;
|
||||||
if (sd == NULL)
|
host = scsi_host_alloc(&scsi_driver_template, sizeof(*sd));
|
||||||
return -ENOMEM;
|
if (host == NULL)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
sd = (struct sbp2_device *) host->hostdata;
|
||||||
unit->device.driver_data = sd;
|
unit->device.driver_data = sd;
|
||||||
sd->unit = unit;
|
sd->unit = unit;
|
||||||
INIT_LIST_HEAD(&sd->orb_list);
|
INIT_LIST_HEAD(&sd->orb_list);
|
||||||
|
@ -631,17 +636,18 @@ static int sbp2_probe(struct device *dev)
|
||||||
sd->address_handler.address_callback = sbp2_status_write;
|
sd->address_handler.address_callback = sbp2_status_write;
|
||||||
sd->address_handler.callback_data = sd;
|
sd->address_handler.callback_data = sd;
|
||||||
|
|
||||||
if (fw_core_add_address_handler(&sd->address_handler,
|
err = fw_core_add_address_handler(&sd->address_handler,
|
||||||
&fw_high_memory_region) < 0) {
|
&fw_high_memory_region);
|
||||||
kfree(sd);
|
if (err < 0)
|
||||||
return -EBUSY;
|
goto fail_host;
|
||||||
}
|
|
||||||
|
|
||||||
if (fw_device_enable_phys_dma(device) < 0) {
|
err = fw_device_enable_phys_dma(device);
|
||||||
fw_core_remove_address_handler(&sd->address_handler);
|
if (err < 0)
|
||||||
kfree(sd);
|
goto fail_address_handler;
|
||||||
return -EBUSY;
|
|
||||||
}
|
err = scsi_add_host(host, &unit->device);
|
||||||
|
if (err < 0)
|
||||||
|
goto fail_address_handler;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan unit directory to get management agent address,
|
* Scan unit directory to get management agent address,
|
||||||
|
@ -695,6 +701,13 @@ static int sbp2_probe(struct device *dev)
|
||||||
kref_get(&sd->kref);
|
kref_get(&sd->kref);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
fail_address_handler:
|
||||||
|
fw_core_remove_address_handler(&sd->address_handler);
|
||||||
|
fail_host:
|
||||||
|
scsi_host_put(host);
|
||||||
|
fail:
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sbp2_remove(struct device *dev)
|
static int sbp2_remove(struct device *dev)
|
||||||
|
@ -881,10 +894,10 @@ complete_command_orb(struct sbp2_orb *base_orb, struct sbp2_status *status)
|
||||||
|
|
||||||
static void sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
|
static void sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
|
||||||
{
|
{
|
||||||
struct fw_unit *unit =
|
struct sbp2_device *sd =
|
||||||
(struct fw_unit *)orb->cmd->device->host->hostdata[0];
|
(struct sbp2_device *)orb->cmd->device->host->hostdata;
|
||||||
|
struct fw_unit *unit = sd->unit;
|
||||||
struct fw_device *device = fw_device(unit->device.parent);
|
struct fw_device *device = fw_device(unit->device.parent);
|
||||||
struct sbp2_device *sd = unit->device.driver_data;
|
|
||||||
struct scatterlist *sg;
|
struct scatterlist *sg;
|
||||||
int sg_len, l, i, j, count;
|
int sg_len, l, i, j, count;
|
||||||
size_t size;
|
size_t size;
|
||||||
|
@ -950,10 +963,10 @@ static void sbp2_command_orb_map_scatterlist(struct sbp2_command_orb *orb)
|
||||||
|
|
||||||
static void sbp2_command_orb_map_buffer(struct sbp2_command_orb *orb)
|
static void sbp2_command_orb_map_buffer(struct sbp2_command_orb *orb)
|
||||||
{
|
{
|
||||||
struct fw_unit *unit =
|
struct sbp2_device *sd =
|
||||||
(struct fw_unit *)orb->cmd->device->host->hostdata[0];
|
(struct sbp2_device *)orb->cmd->device->host->hostdata;
|
||||||
|
struct fw_unit *unit = sd->unit;
|
||||||
struct fw_device *device = fw_device(unit->device.parent);
|
struct fw_device *device = fw_device(unit->device.parent);
|
||||||
struct sbp2_device *sd = unit->device.driver_data;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As for map_scatterlist, we need to fill in the high bits of
|
* As for map_scatterlist, we need to fill in the high bits of
|
||||||
|
@ -975,9 +988,10 @@ static void sbp2_command_orb_map_buffer(struct sbp2_command_orb *orb)
|
||||||
|
|
||||||
static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
|
static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
|
||||||
{
|
{
|
||||||
struct fw_unit *unit = (struct fw_unit *)cmd->device->host->hostdata[0];
|
struct sbp2_device *sd =
|
||||||
|
(struct sbp2_device *)cmd->device->host->hostdata;
|
||||||
|
struct fw_unit *unit = sd->unit;
|
||||||
struct fw_device *device = fw_device(unit->device.parent);
|
struct fw_device *device = fw_device(unit->device.parent);
|
||||||
struct sbp2_device *sd = unit->device.driver_data;
|
|
||||||
struct sbp2_command_orb *orb;
|
struct sbp2_command_orb *orb;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1067,8 +1081,7 @@ static int sbp2_scsi_queuecommand(struct scsi_cmnd *cmd, scsi_done_fn_t done)
|
||||||
|
|
||||||
static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
|
static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
|
||||||
{
|
{
|
||||||
struct fw_unit *unit = (struct fw_unit *)sdev->host->hostdata[0];
|
struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata;
|
||||||
struct sbp2_device *sd = unit->device.driver_data;
|
|
||||||
|
|
||||||
sdev->allow_restart = 1;
|
sdev->allow_restart = 1;
|
||||||
|
|
||||||
|
@ -1079,8 +1092,8 @@ static int sbp2_scsi_slave_alloc(struct scsi_device *sdev)
|
||||||
|
|
||||||
static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
|
static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
|
||||||
{
|
{
|
||||||
struct fw_unit *unit = (struct fw_unit *)sdev->host->hostdata[0];
|
struct sbp2_device *sd = (struct sbp2_device *)sdev->host->hostdata;
|
||||||
struct sbp2_device *sd = unit->device.driver_data;
|
struct fw_unit *unit = sd->unit;
|
||||||
|
|
||||||
sdev->use_10_for_rw = 1;
|
sdev->use_10_for_rw = 1;
|
||||||
|
|
||||||
|
@ -1103,7 +1116,9 @@ static int sbp2_scsi_slave_configure(struct scsi_device *sdev)
|
||||||
*/
|
*/
|
||||||
static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
|
static int sbp2_scsi_abort(struct scsi_cmnd *cmd)
|
||||||
{
|
{
|
||||||
struct fw_unit *unit = (struct fw_unit *)cmd->device->host->hostdata[0];
|
struct sbp2_device *sd =
|
||||||
|
(struct sbp2_device *)cmd->device->host->hostdata;
|
||||||
|
struct fw_unit *unit = sd->unit;
|
||||||
|
|
||||||
fw_notify("sbp2_scsi_abort\n");
|
fw_notify("sbp2_scsi_abort\n");
|
||||||
sbp2_agent_reset(unit);
|
sbp2_agent_reset(unit);
|
||||||
|
@ -1127,55 +1142,6 @@ static struct scsi_host_template scsi_driver_template = {
|
||||||
.can_queue = 1,
|
.can_queue = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int add_scsi_devices(struct fw_unit *unit)
|
|
||||||
{
|
|
||||||
struct sbp2_device *sd = unit->device.driver_data;
|
|
||||||
int retval, lun;
|
|
||||||
|
|
||||||
if (sd->scsi_host != NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
sd->scsi_host = scsi_host_alloc(&scsi_driver_template,
|
|
||||||
sizeof(unsigned long));
|
|
||||||
if (sd->scsi_host == NULL) {
|
|
||||||
fw_error("failed to register scsi host\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sd->scsi_host->hostdata[0] = (unsigned long)unit;
|
|
||||||
retval = scsi_add_host(sd->scsi_host, &unit->device);
|
|
||||||
if (retval < 0) {
|
|
||||||
fw_error("failed to add scsi host\n");
|
|
||||||
scsi_host_put(sd->scsi_host);
|
|
||||||
sd->scsi_host = NULL;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* FIXME: Loop over luns here. */
|
|
||||||
lun = 0;
|
|
||||||
retval = scsi_add_device(sd->scsi_host, 0, 0, lun);
|
|
||||||
if (retval < 0) {
|
|
||||||
fw_error("failed to add scsi device\n");
|
|
||||||
scsi_remove_host(sd->scsi_host);
|
|
||||||
scsi_host_put(sd->scsi_host);
|
|
||||||
sd->scsi_host = NULL;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void remove_scsi_devices(struct fw_unit *unit)
|
|
||||||
{
|
|
||||||
struct sbp2_device *sd = unit->device.driver_data;
|
|
||||||
|
|
||||||
if (sd->scsi_host != NULL) {
|
|
||||||
scsi_remove_host(sd->scsi_host);
|
|
||||||
scsi_host_put(sd->scsi_host);
|
|
||||||
}
|
|
||||||
sd->scsi_host = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
|
MODULE_AUTHOR("Kristian Hoegsberg <krh@bitplanet.net>");
|
||||||
MODULE_DESCRIPTION("SCSI over IEEE1394");
|
MODULE_DESCRIPTION("SCSI over IEEE1394");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
Loading…
Reference in a new issue