diff --git a/scst/ChangeLog b/scst/ChangeLog index 79b08f4b6..fb35753f7 100644 --- a/scst/ChangeLog +++ b/scst/ChangeLog @@ -8,7 +8,7 @@ Summary of changes between versions 0.9.5 and 0.9.6 implemented full support for SCSI task attributes (SIMPLE, ORDERED, etc.). - - Updated to work on 2.6.20.x + - Updated to work on 2.6.20.x, no update for 2.6.21.x is needed - Updated to work on 2.6.19.x, thanks to Ming Zhang. @@ -18,6 +18,10 @@ Summary of changes between versions 0.9.5 and 0.9.6 - /proc implementation moved to seq_*() library, thanks to Ming Zhang. Target drivers need to be updated accordingly. + - Linear search in the LUN translation routines scst_translate_lun() + and scst_mgmt_translate_lun() was changed to a hash-based one, thanks + to Michael G. Byrnes. + - Building from the Linux kernel tree updated, inside kernel building fixed. - Support for CPU cache flushing before doing DMA to target devices added. diff --git a/scst/README b/scst/README index 5defe8743..2e1c61358 100644 --- a/scst/README +++ b/scst/README @@ -559,4 +559,6 @@ Thanks to: code and Vu Pham who updated it for the VDISK dev handler. + * Michael G. Byrnes for fixes. + Vladislav Bolkhovitin , http://scst.sourceforge.net diff --git a/scst/include/scsi_tgt.h b/scst/include/scsi_tgt.h index 51d57ac17..bf5b8b534 100644 --- a/scst/include/scsi_tgt.h +++ b/scst/include/scsi_tgt.h @@ -797,6 +797,11 @@ struct scst_tgt void *tgt_priv; }; +/* Hash size and hash fn for hash based lun translation */ +#define TGT_DEV_HASH_SHIFT 5 +#define TGT_DEV_HASH_SIZE (1<sess_tgt_dev_list */ + /* List entry in sess->sess_tgt_dev_list_hash */ struct list_head sess_tgt_dev_list_entry; struct scst_device *dev; /* to save extra dereferences */ diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index b2acdf0a5..69a57ebe9 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -390,6 +390,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess, int ini_sg, ini_unchecked_isa_dma, ini_use_clustering; struct scst_tgt_dev *tgt_dev; struct scst_device *dev = acg_dev->dev; + struct list_head *sess_tgt_dev_list_head; int rc, i; TRACE_ENTRY(); @@ -451,7 +452,7 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess, tgt_dev->p_cmd_lists = &scst_main_cmd_lists; if (dev->scsi_dev != NULL) { - TRACE(TRACE_DEBUG, "host=%d, channel=%d, id=%d, lun=%d, " + TRACE_DBG("host=%d, channel=%d, id=%d, lun=%d, " "SCST lun=%Ld", dev->scsi_dev->host->host_no, dev->scsi_dev->channel, dev->scsi_dev->id, dev->scsi_dev->lun, (uint64_t)tgt_dev->lun); @@ -527,8 +528,9 @@ static struct scst_tgt_dev *scst_alloc_add_tgt_dev(struct scst_session *sess, if (dev->dev_reserved) __set_bit(SCST_TGT_DEV_RESERVED, &tgt_dev->tgt_dev_flags); - list_add_tail(&tgt_dev->sess_tgt_dev_list_entry, - &sess->sess_tgt_dev_list); + sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[HASH_VAL(tgt_dev->lun)]; + list_add_tail(&tgt_dev->sess_tgt_dev_list_entry, sess_tgt_dev_list_head); out: TRACE_EXIT(); @@ -623,7 +625,6 @@ int scst_sess_alloc_tgt_devs(struct scst_session *sess) TRACE_ENTRY(); - INIT_LIST_HEAD(&sess->sess_tgt_dev_list); list_for_each_entry(acg_dev, &sess->acg->acg_dev_list, acg_dev_list_entry) { @@ -646,17 +647,21 @@ out_free: /* scst_mutex supposed to be held and activity suspended */ void scst_sess_free_tgt_devs(struct scst_session *sess) { + int i; struct scst_tgt_dev *tgt_dev, *t; TRACE_ENTRY(); /* The session is going down, no users, so no locks */ - list_for_each_entry_safe(tgt_dev, t, &sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { - scst_free_tgt_dev(tgt_dev); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry_safe(tgt_dev, t, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + scst_free_tgt_dev(tgt_dev); + } + INIT_LIST_HEAD(sess_tgt_dev_list_head); } - INIT_LIST_HEAD(&sess->sess_tgt_dev_list); TRACE_EXIT(); return; @@ -1065,6 +1070,7 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask, const char *initiator_name) { struct scst_session *sess; + int i; int len; char *nm; @@ -1086,7 +1092,11 @@ struct scst_session *scst_alloc_session(struct scst_tgt *tgt, int gfp_mask, sess->init_phase = SCST_SESS_IPH_INITING; atomic_set(&sess->refcnt, 0); - INIT_LIST_HEAD(&sess->sess_tgt_dev_list); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + INIT_LIST_HEAD(sess_tgt_dev_list_head); + } spin_lock_init(&sess->sess_list_lock); INIT_LIST_HEAD(&sess->search_cmd_list); sess->tgt = tgt; diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 08aa15fa0..91230bc00 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -1240,6 +1240,7 @@ static int scst_report_luns_local(struct scst_cmd *cmd) int res = SCST_EXEC_COMPLETED; int dev_cnt = 0; int buffer_size; + int i; struct scst_tgt_dev *tgt_dev = NULL; uint8_t *buffer; int offs, overflow = 0; @@ -1267,35 +1268,38 @@ static int scst_report_luns_local(struct scst_cmd *cmd) memset(buffer, 0, buffer_size); offs = 8; - /* sess->sess_tgt_dev_list is protected by suspended activity */ - list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { - if (!overflow) { - if (offs >= buffer_size) { - scst_put_buf(cmd, buffer); - buffer_size = scst_get_buf_next(cmd, &buffer); - if (buffer_size > 0) { - memset(buffer, 0, buffer_size); - offs = 0; - } else { - overflow = 1; - goto inc_dev_cnt; + /* sess->sess_tgt_dev_list_hash is protected by suspended activity */ + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &cmd->sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + if (!overflow) { + if (offs >= buffer_size) { + scst_put_buf(cmd, buffer); + buffer_size = scst_get_buf_next(cmd, &buffer); + if (buffer_size > 0) { + memset(buffer, 0, buffer_size); + offs = 0; + } else { + overflow = 1; + goto inc_dev_cnt; + } } + if ((buffer_size - offs) < 8) { + PRINT_ERROR_PR("Buffer allocated for REPORT " + "LUNS command doesn't allow to fit 8 " + "byte entry (buffer_size=%d)", + buffer_size); + goto out_put_hw_err; + } + buffer[offs] = (tgt_dev->lun >> 8) & 0xff; + buffer[offs+1] = tgt_dev->lun & 0xff; + offs += 8; } - if ((buffer_size - offs) < 8) { - PRINT_ERROR_PR("Buffer allocated for REPORT " - "LUNS command doesn't allow to fit 8 " - "byte entry (buffer_size=%d)", - buffer_size); - goto out_put_hw_err; - } - buffer[offs] = (tgt_dev->lun >> 8) & 0xff; - buffer[offs+1] = tgt_dev->lun & 0xff; - offs += 8; - } inc_dev_cnt: - dev_cnt++; + dev_cnt++; + } } if (!overflow) scst_put_buf(cmd, buffer); @@ -2580,12 +2584,13 @@ static int scst_translate_lun(struct scst_cmd *cmd) __scst_get(1); if (likely(!test_bit(SCST_FLAG_SUSPENDED, &scst_flags))) { - res = -1; + struct list_head *sess_tgt_dev_list_head = + &cmd->sess->sess_tgt_dev_list_hash[HASH_VAL(cmd->lun)]; TRACE_DBG("Finding tgt_dev for cmd %p (lun %Ld)", cmd, - (uint64_t)cmd->lun); - list_for_each_entry(tgt_dev, &cmd->sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { + (uint64_t)cmd->lun); + res = -1; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { if (tgt_dev->lun == cmd->lun) { TRACE_DBG("tgt_dev %p found", tgt_dev); @@ -2988,6 +2993,7 @@ void scst_cmd_tasklet(long p) static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd) { struct scst_tgt_dev *tgt_dev = NULL; + struct list_head *sess_tgt_dev_list_head; int res = -1; TRACE_ENTRY(); @@ -3005,9 +3011,10 @@ static int scst_mgmt_translate_lun(struct scst_mgmt_cmd *mcmd) goto out; } - list_for_each_entry(tgt_dev, &mcmd->sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { + sess_tgt_dev_list_head = + &mcmd->sess->sess_tgt_dev_list_hash[HASH_VAL(mcmd->lun)]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { if (tgt_dev->lun == mcmd->lun) { TRACE_DBG("tgt_dev %p found", tgt_dev); mcmd->mcmd_tgt_dev = tgt_dev; @@ -3514,6 +3521,7 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd, int nexus_loss) { int res; + int i; struct scst_session *sess = mcmd->sess; struct scst_tgt_dev *tgt_dev; @@ -3528,23 +3536,26 @@ static int scst_abort_all_nexus_loss_sess(struct scst_mgmt_cmd *mcmd, } down(&scst_mutex); - list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { - struct scst_device *dev = tgt_dev->dev; - int rc; - - spin_lock_bh(&dev->dev_lock); - __scst_block_dev(dev); - spin_unlock_bh(&dev->dev_lock); - - __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); - if (nexus_loss) - scst_reset_tgt_dev(tgt_dev, 1); - - rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); - if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) - mcmd->status = rc; + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + struct scst_device *dev = tgt_dev->dev; + int rc; + + spin_lock_bh(&dev->dev_lock); + __scst_block_dev(dev); + spin_unlock_bh(&dev->dev_lock); + + __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); + if (nexus_loss) + scst_reset_tgt_dev(tgt_dev, 1); + + rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); + if ((rc < 0) && (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) + mcmd->status = rc; + } } up(&scst_mutex); @@ -3559,6 +3570,7 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd, int nexus_loss) { int res; + int i; struct scst_tgt *tgt = mcmd->sess->tgt; struct scst_session *sess; struct scst_device *dev; @@ -3583,19 +3595,22 @@ static int scst_abort_all_nexus_loss_tgt(struct scst_mgmt_cmd *mcmd, } list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) { - list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) - { - int rc; - - __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); - if (nexus_loss) - scst_reset_tgt_dev(tgt_dev, 1); - - rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); - if ((rc < 0) && - (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) - mcmd->status = rc; + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + int rc; + + __scst_abort_task_set(mcmd, tgt_dev, !nexus_loss, 1); + if (nexus_loss) + scst_reset_tgt_dev(tgt_dev, 1); + + rc = scst_call_dev_task_mgmt_fn(mcmd, tgt_dev, 0); + if ((rc < 0) && + (mcmd->status == SCST_MGMT_STATUS_SUCCESS)) + mcmd->status = rc; + } } } @@ -3720,14 +3735,22 @@ static void scst_mgmt_cmd_send_done(struct scst_mgmt_cmd *mcmd) case SCST_NEXUS_LOSS_SESS: case SCST_ABORT_ALL_TASKS_SESS: + { + int i; + down(&scst_mutex); - list_for_each_entry(tgt_dev, &mcmd->sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) { - scst_unblock_dev(tgt_dev->dev); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &mcmd->sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + scst_unblock_dev(tgt_dev->dev); + } } up(&scst_mutex); - break; + break; + } case SCST_CLEAR_ACA: default: break; @@ -4205,6 +4228,7 @@ static void scst_unreg_work_fn(void *p) static void scst_unreg_work_fn(struct work_struct *work) #endif { + int i; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) struct scst_session *sess = (struct scst_session*)p; #else @@ -4216,15 +4240,19 @@ static void scst_unreg_work_fn(struct work_struct *work) TRACE_ENTRY(); down(&scst_mutex); - list_for_each_entry(tgt_dev, &sess->sess_tgt_dev_list, - sess_tgt_dev_list_entry) { - struct scst_dev_type *handler = tgt_dev->dev->handler; - if (handler && handler->pre_unreg_sess) { - TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)", - tgt_dev); - handler->pre_unreg_sess(tgt_dev); - TRACE_DBG("%s", "Dev handler's pre_unreg_sess() " - "returned"); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + struct scst_dev_type *handler = tgt_dev->dev->handler; + if (handler && handler->pre_unreg_sess) { + TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)", + tgt_dev); + handler->pre_unreg_sess(tgt_dev); + TRACE_DBG("%s", "Dev handler's pre_unreg_sess() " + "returned"); + } } } up(&scst_mutex);