Re: [PATCH update 3/3] firewire: fw-sbp2: add support for multiple logical units per target

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 7/28/07, Stefan Richter <stefanr@xxxxxxxxxxxxxxxxx> wrote:
> This makes multiple logical units on a single target accessible to
> fw-sbp2.  Successfully tested with the IOI FWB-IDE01AB dual LU bridge.

Very nice, this is good code.  I have a couple of nitpicks below.

> Signed-off-by: Stefan Richter <stefanr@xxxxxxxxxxxxxxxxx>
> ---
> update:
>    - dynamically append logical units in a list
>    - simplify config ROM parsing
>
>  drivers/firewire/fw-sbp2.c |  195 ++++++++++++++++++++++++-------------
>  1 file changed, 130 insertions(+), 65 deletions(-)
>
> Index: linux/drivers/firewire/fw-sbp2.c
> ===================================================================
> --- linux.orig/drivers/firewire/fw-sbp2.c
> +++ linux/drivers/firewire/fw-sbp2.c
> @@ -71,6 +71,7 @@ static const char sbp2_driver_name[] = "
>
>  struct sbp2_logical_unit {
>         struct sbp2_target *tgt;
> +       struct list_head tgt_list;

I would call this link. I've consistently named all instances of
struct list_head that are used as a list link either 'link'
'something_link'.  I find that it's a helpful convention for figuring
out/remembering whether the field is a list head or the link part of
an element in a list.

>         struct scsi_device *sdev;
>         struct fw_address_handler address_handler;
>         struct list_head orb_list;
> @@ -100,7 +101,7 @@ struct sbp2_target {
>
>         unsigned workarounds;
>         int starget_id;
> -       struct sbp2_logical_unit lu[1];
> +       struct list_head lu_list;

The other convention I've used is to call fields of type struct
list_head that are used as the head of a list 'something_list' so this
is nicely in line with that.

>  };
>
>  #define SBP2_MAX_SG_ELEMENT_LENGTH     0xf000
> @@ -113,7 +114,9 @@ struct sbp2_target {
>  #define SBP2_DIRECTION_FROM_MEDIA      0x1
>
>  /* Unit directory keys */
> -#define SBP2_FIRMWARE_REVISION         0x3c
> +#define SBP2_CSR_FIRMWARE_REVISION     0x3c
> +#define SBP2_CSR_LOGICAL_UNIT_NUMBER   0x14
> +#define SBP2_CSR_LOGICAL_UNIT_DIRECTORY        0xd4
>
>  /* Flags for detected oddities and brokeness */
>  #define SBP2_WORKAROUND_128K_MAX_TRANS 0x1
> @@ -531,18 +534,21 @@ static int sbp2_agent_reset(struct sbp2_
>         return 0;
>  }
>
> -/*  FIXME: Loop over logical units */
>  static void release_sbp2_device(struct kref *kref)
>  {
>         struct sbp2_target *tgt = container_of(kref, struct sbp2_target, kref);
> -       struct sbp2_logical_unit *lu = tgt->lu;
> +       struct sbp2_logical_unit *lu, *next;
>
> -       if (lu->sdev)
> -               scsi_remove_device(lu->sdev);
> +       list_for_each_entry_safe(lu, next, &tgt->lu_list, tgt_list) {
> +               if (lu->sdev)
> +                       scsi_remove_device(lu->sdev);
>
> -       sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
> -                                SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
> -       fw_core_remove_address_handler(&lu->address_handler);
> +               sbp2_send_management_orb(lu, tgt->node_id, lu->generation,
> +                               SBP2_LOGOUT_REQUEST, lu->login_id, NULL);
> +               fw_core_remove_address_handler(&lu->address_handler);
> +               list_del(&lu->tgt_list);
> +               kfree(lu);
> +       }
>         fw_notify("removed sbp2 unit %s\n", tgt->unit->device.bus_id);
>         put_device(&tgt->unit->device);
>         kfree(tgt);
> @@ -623,70 +629,122 @@ static void sbp2_login(struct work_struc
>         kref_put(&lu->tgt->kref, release_sbp2_device);
>  }
>
> -static atomic_t sbp2_starget_id = ATOMIC_INIT(-1);
> -
> -/* FIXME: Loop over luns here. */
> -static int sbp2_probe(struct device *dev)
> +static int sbp2_add_logical_unit(struct sbp2_target *tgt, int lun_entry)
>  {
> -       struct fw_unit *unit = fw_unit(dev);
> -       struct fw_device *device = fw_device(unit->device.parent);
> -       struct sbp2_target *tgt;
>         struct sbp2_logical_unit *lu;
> -       struct fw_csr_iterator ci;
> -       int i, key, value, error;
> -       u32 model, firmware_revision;
>
> -       error = -ENOMEM;
> -       tgt = kzalloc(sizeof(*tgt), GFP_KERNEL);
> -       if (!tgt)
> -               goto out_error;
> +       lu = kmalloc(sizeof(*lu), GFP_KERNEL);
> +       if (!lu)
> +               return -ENOMEM;
>
> -       unit->device.driver_data = tgt;
> -       tgt->unit = unit;
> -       kref_init(&tgt->kref);
> -       tgt->starget_id = atomic_inc_return(&sbp2_starget_id);
> +       lu->address_handler.length           = 0x100;
> +       lu->address_handler.address_callback = sbp2_status_write;
> +       lu->address_handler.callback_data    = lu;
> +
> +       if (fw_core_add_address_handler(&lu->address_handler,
> +                                       &fw_high_memory_region) < 0) {
> +               kfree(lu);
> +               return -ENOMEM;
> +       }
>
> -       lu = tgt->lu;
> -       lu->tgt = tgt;
> -       lu->lun = 0;
> +       lu->tgt  = tgt;
> +       lu->sdev = NULL;
> +       lu->lun  = lun_entry & 0xffff;
> +       lu->retries = 0;
>         INIT_LIST_HEAD(&lu->orb_list);
> +       INIT_DELAYED_WORK(&lu->work, sbp2_login);
>
> -       lu->address_handler.length = 0x100;
> -       lu->address_handler.address_callback = sbp2_status_write;
> -       lu->address_handler.callback_data = lu;
> +       list_add_tail(&lu->tgt_list, &tgt->lu_list);
> +       return 0;
> +}
>
> -       error = fw_core_add_address_handler(&lu->address_handler,
> -                                           &fw_high_memory_region);
> -       if (error < 0)
> -               goto out_free;
> +static int sbp2_scan_logical_unit_dir(struct sbp2_target *tgt, u32 *directory)
> +{
> +       struct fw_csr_iterator ci;
> +       int key, value;
> +
> +       fw_csr_iterator_init(&ci, directory);
> +       while (fw_csr_iterator_next(&ci, &key, &value))
> +               if (key == SBP2_CSR_LOGICAL_UNIT_NUMBER &&
> +                   sbp2_add_logical_unit(tgt, value) < 0)
> +                       return -ENOMEM;
> +       return 0;
> +}
>
> -       error = fw_device_enable_phys_dma(device);
> -       if (error < 0)
> -               goto out_remove_address_handler;
> +static int sbp2_scan_unit_dir(struct sbp2_target *tgt, u32 *directory,
> +                             u32 *model, u32 *firmware_revision)
> +{
> +       struct fw_device *dev = fw_device(tgt->unit->device.parent);
> +       struct fw_csr_iterator ci;
> +       int key, value;
> +       u32 *subdir;
>
> -       /*
> -        * Scan unit directory to get management agent address,
> -        * firmware revison and model.  Initialize firmware_revision
> -        * and model to values that wont match anything in our table.
> -        */
> -       firmware_revision = 0xff000000;
> -       model = 0xff000000;
> -       fw_csr_iterator_init(&ci, unit->directory);
> +       fw_csr_iterator_init(&ci, directory);
>         while (fw_csr_iterator_next(&ci, &key, &value)) {
>                 switch (key) {
> +
>                 case CSR_DEPENDENT_INFO | CSR_OFFSET:
> -                       tgt->management_agent_address =
> -                               0xfffff0000000ULL + 4 * value;
> -                       break;
> -               case SBP2_FIRMWARE_REVISION:
> -                       firmware_revision = value;
> +                       tgt->management_agent_address
> +                                       = 0xfffff0000000ULL + 4 * value;
>                         break;
> +
>                 case CSR_MODEL:
> -                       model = value;
> +                       *model = value;
> +                       break;
> +
> +               case SBP2_CSR_FIRMWARE_REVISION:
> +                       *firmware_revision = value;
> +                       break;
> +
> +               case SBP2_CSR_LOGICAL_UNIT_NUMBER:
> +                       if (sbp2_add_logical_unit(tgt, value) < 0)
> +                               return -ENOMEM;
> +                       break;
> +
> +               case SBP2_CSR_LOGICAL_UNIT_DIRECTORY:
> +                       subdir = ci.p + value;
> +                       if (subdir <= dev->config_rom + 5 ||
> +                           subdir >= dev->config_rom + dev->config_rom_length)
> +                               fw_error("logical unit dir out of bounds\n");

This check isn't necessary, read_bus_info_block ensures that all
blocks read are within the config rom area.

> +                       else if (sbp2_scan_logical_unit_dir(tgt, subdir) < 0)
> +                               return -ENOMEM;
>                         break;
>                 }
>         }
> +       return 0;
> +}
> +
> +static atomic_t sbp2_starget_id = ATOMIC_INIT(-1);
> +
> +static int sbp2_probe(struct device *dev)
> +{
> +       struct fw_unit *unit = fw_unit(dev);
> +       struct fw_device *device = fw_device(unit->device.parent);
> +       struct sbp2_target *tgt;
> +       struct sbp2_logical_unit *lu, *next;
> +       int i;
> +       u32 model, firmware_revision;
> +
> +       tgt = kmalloc(sizeof(*tgt), GFP_KERNEL);
> +       if (!tgt)
> +               goto out_error;
> +
> +       unit->device.driver_data = tgt;
> +       tgt->unit = unit;
> +       kref_init(&tgt->kref);
> +       INIT_LIST_HEAD(&tgt->lu_list);
> +
> +       /* Initialize to values that won't match anything in our table. */
> +       model = ~0;
> +       firmware_revision = ~0;
> +       if (sbp2_scan_unit_dir(tgt, unit->directory, &model,
> +                              &firmware_revision) < 0)
> +               goto out_free;
> +
> +       if (fw_device_enable_phys_dma(device) < 0)
> +               goto out_free;
>
> +       tgt->workarounds = 0;
>         for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
>                 if (sbp2_workarounds_table[i].firmware_revision !=
>                     (firmware_revision & 0xffffff00))
> @@ -704,24 +762,29 @@ static int sbp2_probe(struct device *dev
>                           unit->device.bus_id,
>                           tgt->workarounds, firmware_revision, model);
>
> +       tgt->starget_id = atomic_inc_return(&sbp2_starget_id);
>         get_device(&unit->device);
>
>         /*
>          * We schedule work to do the login so we can easily reschedule retries.
>          * Always get the ref when scheduling work.
>          */
> -       INIT_DELAYED_WORK(&lu->work, sbp2_login);
> -       if (schedule_delayed_work(&lu->work, 0))
> -               kref_get(&tgt->kref);
> +       list_for_each_entry(lu, &tgt->lu_list, tgt_list)
> +               if (schedule_delayed_work(&lu->work, 0))
> +                       kref_get(&tgt->kref);
>
>         return 0;
>
> - out_remove_address_handler:
> -       fw_core_remove_address_handler(&lu->address_handler);
>   out_free:
> +       list_for_each_entry_safe(lu, next, &tgt->lu_list, tgt_list) {
> +               fw_core_remove_address_handler(&lu->address_handler);
> +               list_del(&lu->tgt_list);
> +               kfree(lu);
> +       }
>         kfree(tgt);
> +
>   out_error:
> -       return error;
> +       return -ENOMEM;
>  }
>
>  static int sbp2_remove(struct device *dev)
> @@ -771,17 +834,19 @@ static void sbp2_reconnect(struct work_s
>         kref_put(&lu->tgt->kref, release_sbp2_device);
>  }
>
> -/*  FIXME: Loop over logical units */
>  static void sbp2_update(struct fw_unit *unit)
>  {
>         struct fw_device *device = fw_device(unit->device.parent);
>         struct sbp2_target *tgt = unit->device.driver_data;
> -       struct sbp2_logical_unit *lu = tgt->lu;
> +       struct sbp2_logical_unit *lu;
>
> -       lu->retries = 0;
>         fw_device_enable_phys_dma(device);
> -       if (schedule_delayed_work(&lu->work, 0))
> -               kref_get(&tgt->kref);
> +
> +       list_for_each_entry(lu, &tgt->lu_list, tgt_list) {
> +               lu->retries = 0;
> +               if (schedule_delayed_work(&lu->work, 0))
> +                       kref_get(&tgt->kref);
> +       }
>  }
>
>  #define SBP2_UNIT_SPEC_ID_ENTRY        0x0000609e
>
> --
> Stefan Richter
> -=====-=-=== -=== ===-=
> http://arcgraph.de/sr/
-
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]
  Powered by Linux