aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJames Smart <James.Smart@Emulex.Com>2006-04-10 10:14:05 -0400
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-04-13 14:25:16 -0400
commitaedf349773e5877d716a89368d512b9baa3e8c7b (patch)
treeacc08d181b97c434c70c7ad984e262813067ba89 /include
parentb0d2364887e94c880680f1e17943cd660bcf8979 (diff)
[SCSI] FC transport: fixes for workq deadlocks
As previously reported via Michael Reed, the FC transport took a hit in 2.6.15 (perhaps a little earlier) when we solved a recursion error. There are 2 deadlocks occurring: - With scan and the delete items sharing the same workq, flushing the workq for the delete code was getting it stalled behind a very long running scan code path. - There's a deadlock where scsi_remove_target() has to sit behind scsi_scan_target() due to contention over the scan_lock(). This patch resolves the 1st deadlock and significantly reduces the odds of the second. So far, we have only replicated the 2nd deadlock on a highly-parallel SMP system. More on the 2nd deadlock in a following email. This patch reworks the transport to: - Only use the scsi host workq for scanning - Use 2 other workq's internally. One for deletions, the other for scheduled deletions. Originally, we tried this with a single workq, but the occassional flushes of the scheduled queues was hitting the second deadlock with a slightly higher frequency. In the future, we'll look at the LLDD's and the transport to see if we can get rid of this extra overhead. - When moving to the other workq's we tightened up some object states and some lock handling. - Properly syncs adds/deletes - minor code cleanups - directly reference fc_host_attrs, rather than through attribute macros - flush the right workq on delayed work cancel failures. Large kudos to Michael Reed who has been working this issue for the last month. Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'include')
-rw-r--r--include/scsi/scsi_transport_fc.h41
1 files changed, 30 insertions, 11 deletions
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h
index cf3fec8be1e3..5626225bd3ae 100644
--- a/include/scsi/scsi_transport_fc.h
+++ b/include/scsi/scsi_transport_fc.h
@@ -202,12 +202,19 @@ struct fc_rport { /* aka fc_starget_attrs */
202 /* internal data */ 202 /* internal data */
203 unsigned int channel; 203 unsigned int channel;
204 u32 number; 204 u32 number;
205 u8 flags;
205 struct list_head peers; 206 struct list_head peers;
206 struct device dev; 207 struct device dev;
207 struct work_struct dev_loss_work; 208 struct work_struct dev_loss_work;
208 struct work_struct scan_work; 209 struct work_struct scan_work;
210 struct work_struct stgt_delete_work;
211 struct work_struct rport_delete_work;
209} __attribute__((aligned(sizeof(unsigned long)))); 212} __attribute__((aligned(sizeof(unsigned long))));
210 213
214/* bit field values for struct fc_rport "flags" field: */
215#define FC_RPORT_DEVLOSS_PENDING 0x01
216#define FC_RPORT_SCAN_PENDING 0x02
217
211#define dev_to_rport(d) \ 218#define dev_to_rport(d) \
212 container_of(d, struct fc_rport, dev) 219 container_of(d, struct fc_rport, dev)
213#define transport_class_to_rport(classdev) \ 220#define transport_class_to_rport(classdev) \
@@ -327,13 +334,16 @@ struct fc_host_attrs {
327 struct list_head rport_bindings; 334 struct list_head rport_bindings;
328 u32 next_rport_number; 335 u32 next_rport_number;
329 u32 next_target_id; 336 u32 next_target_id;
330 u8 flags;
331 struct work_struct rport_del_work;
332};
333 337
334/* values for struct fc_host_attrs "flags" field: */ 338 /* work queues for rport state manipulation */
335#define FC_SHOST_RPORT_DEL_SCHEDULED 0x01 339 char work_q_name[KOBJ_NAME_LEN];
340 struct workqueue_struct *work_q;
341 char devloss_work_q_name[KOBJ_NAME_LEN];
342 struct workqueue_struct *devloss_work_q;
343};
336 344
345#define shost_to_fc_host(x) \
346 ((struct fc_host_attrs *)(x)->shost_data)
337 347
338#define fc_host_node_name(x) \ 348#define fc_host_node_name(x) \
339 (((struct fc_host_attrs *)(x)->shost_data)->node_name) 349 (((struct fc_host_attrs *)(x)->shost_data)->node_name)
@@ -375,10 +385,14 @@ struct fc_host_attrs {
375 (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number) 385 (((struct fc_host_attrs *)(x)->shost_data)->next_rport_number)
376#define fc_host_next_target_id(x) \ 386#define fc_host_next_target_id(x) \
377 (((struct fc_host_attrs *)(x)->shost_data)->next_target_id) 387 (((struct fc_host_attrs *)(x)->shost_data)->next_target_id)
378#define fc_host_flags(x) \ 388#define fc_host_work_q_name(x) \
379 (((struct fc_host_attrs *)(x)->shost_data)->flags) 389 (((struct fc_host_attrs *)(x)->shost_data)->work_q_name)
380#define fc_host_rport_del_work(x) \ 390#define fc_host_work_q(x) \
381 (((struct fc_host_attrs *)(x)->shost_data)->rport_del_work) 391 (((struct fc_host_attrs *)(x)->shost_data)->work_q)
392#define fc_host_devloss_work_q_name(x) \
393 (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q_name)
394#define fc_host_devloss_work_q(x) \
395 (((struct fc_host_attrs *)(x)->shost_data)->devloss_work_q)
382 396
383 397
384/* The functions by which the transport class and the driver communicate */ 398/* The functions by which the transport class and the driver communicate */
@@ -461,10 +475,15 @@ fc_remote_port_chkready(struct fc_rport *rport)
461 475
462 switch (rport->port_state) { 476 switch (rport->port_state) {
463 case FC_PORTSTATE_ONLINE: 477 case FC_PORTSTATE_ONLINE:
464 result = 0; 478 if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
479 result = 0;
480 else if (rport->flags & FC_RPORT_DEVLOSS_PENDING)
481 result = DID_IMM_RETRY << 16;
482 else
483 result = DID_NO_CONNECT << 16;
465 break; 484 break;
466 case FC_PORTSTATE_BLOCKED: 485 case FC_PORTSTATE_BLOCKED:
467 result = DID_BUS_BUSY << 16; 486 result = DID_IMM_RETRY << 16;
468 break; 487 break;
469 default: 488 default:
470 result = DID_NO_CONNECT << 16; 489 result = DID_NO_CONNECT << 16;