diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2005-05-24 13:06:38 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-05-26 11:27:53 -0400 |
commit | a283bd37d00e92e8874ca6325ae071691d4db388 (patch) | |
tree | 4c436d59fc326e3545c575a88b92fd31ace841a5 | |
parent | 631e8a1398ce4cfef8b30678d51daf0c64313a09 (diff) |
[SCSI] Add target alloc/destroy callbacks to the host template
This gives the HBA driver notice when a target is created and
destroyed to allow it to manage its own target based allocations
accordingly.
This is a much reduced verson of the original patch sent in by
James.Smart@Emulex.com
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/scsi/scsi_scan.c | 24 | ||||
-rw-r--r-- | include/scsi/scsi_device.h | 4 | ||||
-rw-r--r-- | include/scsi/scsi_host.h | 25 |
3 files changed, 49 insertions, 4 deletions
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 588611568d14..4d273ceb1d09 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -293,6 +293,10 @@ static void scsi_target_dev_release(struct device *dev) | |||
293 | { | 293 | { |
294 | struct device *parent = dev->parent; | 294 | struct device *parent = dev->parent; |
295 | struct scsi_target *starget = to_scsi_target(dev); | 295 | struct scsi_target *starget = to_scsi_target(dev); |
296 | struct Scsi_Host *shost = dev_to_shost(parent); | ||
297 | |||
298 | if (shost->hostt->target_destroy) | ||
299 | shost->hostt->target_destroy(starget); | ||
296 | kfree(starget); | 300 | kfree(starget); |
297 | put_device(parent); | 301 | put_device(parent); |
298 | } | 302 | } |
@@ -360,9 +364,23 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
360 | list_add_tail(&starget->siblings, &shost->__targets); | 364 | list_add_tail(&starget->siblings, &shost->__targets); |
361 | spin_unlock_irqrestore(shost->host_lock, flags); | 365 | spin_unlock_irqrestore(shost->host_lock, flags); |
362 | /* allocate and add */ | 366 | /* allocate and add */ |
363 | transport_setup_device(&starget->dev); | 367 | transport_setup_device(dev); |
364 | device_add(&starget->dev); | 368 | device_add(dev); |
365 | transport_add_device(&starget->dev); | 369 | transport_add_device(dev); |
370 | if (shost->hostt->target_alloc) { | ||
371 | int error = shost->hostt->target_alloc(starget); | ||
372 | |||
373 | if(error) { | ||
374 | dev_printk(KERN_ERR, dev, "target allocation failed, error %d\n", error); | ||
375 | /* don't want scsi_target_reap to do the final | ||
376 | * put because it will be under the host lock */ | ||
377 | get_device(dev); | ||
378 | scsi_target_reap(starget); | ||
379 | put_device(dev); | ||
380 | return NULL; | ||
381 | } | ||
382 | } | ||
383 | |||
366 | return starget; | 384 | return starget; |
367 | 385 | ||
368 | found: | 386 | found: |
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index c018020d9160..63c91dd85ca1 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h | |||
@@ -154,7 +154,9 @@ struct scsi_target { | |||
154 | unsigned int id; /* target id ... replace | 154 | unsigned int id; /* target id ... replace |
155 | * scsi_device.id eventually */ | 155 | * scsi_device.id eventually */ |
156 | unsigned long create:1; /* signal that it needs to be added */ | 156 | unsigned long create:1; /* signal that it needs to be added */ |
157 | unsigned long starget_data[0]; | 157 | void *hostdata; /* available to low-level driver */ |
158 | unsigned long starget_data[0]; /* for the transport */ | ||
159 | /* starget_data must be the last element!!!! */ | ||
158 | } __attribute__((aligned(sizeof(unsigned long)))); | 160 | } __attribute__((aligned(sizeof(unsigned long)))); |
159 | 161 | ||
160 | #define to_scsi_target(d) container_of(d, struct scsi_target, dev) | 162 | #define to_scsi_target(d) container_of(d, struct scsi_target, dev) |
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 1cee1e100943..db9914adeac9 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h | |||
@@ -10,6 +10,7 @@ struct block_device; | |||
10 | struct module; | 10 | struct module; |
11 | struct scsi_cmnd; | 11 | struct scsi_cmnd; |
12 | struct scsi_device; | 12 | struct scsi_device; |
13 | struct scsi_target; | ||
13 | struct Scsi_Host; | 14 | struct Scsi_Host; |
14 | struct scsi_host_cmd_pool; | 15 | struct scsi_host_cmd_pool; |
15 | struct scsi_transport_template; | 16 | struct scsi_transport_template; |
@@ -228,6 +229,30 @@ struct scsi_host_template { | |||
228 | void (* slave_destroy)(struct scsi_device *); | 229 | void (* slave_destroy)(struct scsi_device *); |
229 | 230 | ||
230 | /* | 231 | /* |
232 | * Before the mid layer attempts to scan for a new device attached | ||
233 | * to a target where no target currently exists, it will call this | ||
234 | * entry in your driver. Should your driver need to allocate any | ||
235 | * structs or perform any other init items in order to send commands | ||
236 | * to a currently unused target, then this is where you can perform | ||
237 | * those allocations. | ||
238 | * | ||
239 | * Return values: 0 on success, non-0 on failure | ||
240 | * | ||
241 | * Status: OPTIONAL | ||
242 | */ | ||
243 | int (* target_alloc)(struct scsi_target *); | ||
244 | |||
245 | /* | ||
246 | * Immediately prior to deallocating the target structure, and | ||
247 | * after all activity to attached scsi devices has ceased, the | ||
248 | * midlayer calls this point so that the driver may deallocate | ||
249 | * and terminate any references to the target. | ||
250 | * | ||
251 | * Status: OPTIONAL | ||
252 | */ | ||
253 | void (* target_destroy)(struct scsi_target *); | ||
254 | |||
255 | /* | ||
231 | * fill in this function to allow the queue depth of this host | 256 | * fill in this function to allow the queue depth of this host |
232 | * to be changeable (on a per device basis). returns either | 257 | * to be changeable (on a per device basis). returns either |
233 | * the current queue depth setting (may be different from what | 258 | * the current queue depth setting (may be different from what |