summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Bottomley <jejb@raven.il.steeleye.com>2003-01-27 22:19:58 -0600
committerJames Bottomley <jejb@raven.il.steeleye.com>2003-01-27 22:19:58 -0600
commit199662cab0f75773cfd3cce0a2d78dac6b78bb84 (patch)
tree109b63a76cd1f55a4051a4e202ed856fe285afe5
parent26638b9d40a2b9bb4a91ada479eb23d5ad609fd7 (diff)
parentcf6381221cdf35248e1a461c856772fe516556da (diff)
Merge raven.il.steeleye.com:/home/jejb/BK/scsi-cmd-changes-2.5.54
into raven.il.steeleye.com:/home/jejb/BK/scsi-cmd-changes-2.5
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c37
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c90
-rw-r--r--drivers/scsi/cpqfcTSinit.c5
-rw-r--r--drivers/scsi/gdth.c8
-rw-r--r--drivers/scsi/gdth_proc.c8
-rw-r--r--drivers/scsi/hosts.c18
-rw-r--r--drivers/scsi/hosts.h3
-rw-r--r--drivers/scsi/scsi.c30
-rw-r--r--drivers/scsi/scsi.h44
-rw-r--r--drivers/scsi/scsi_error.c2
-rw-r--r--drivers/scsi/scsi_lib.c151
-rw-r--r--drivers/scsi/scsi_scan.c3
-rw-r--r--drivers/scsi/scsi_syms.c7
13 files changed, 323 insertions, 83 deletions
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index 05edbed59319..87a1c3a5c982 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -971,7 +971,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
struct ahd_linux_device *dev;
u_long flags;
- ahd = *(struct ahd_softc **)cmd->host->hostdata;
+ ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
/*
* Save the callback on completion function.
@@ -995,8 +995,8 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
ahd_midlayer_entrypoint_unlock(ahd, &flags);
return (0);
}
- dev = ahd_linux_get_device(ahd, cmd->channel, cmd->target,
- cmd->lun, /*alloc*/TRUE);
+ dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id,
+ cmd->device->lun, /*alloc*/TRUE);
if (dev == NULL) {
ahd_midlayer_entrypoint_unlock(ahd, &flags);
printf("aic79xx_linux_queue: Unable to allocate device!\n");
@@ -1217,7 +1217,7 @@ ahd_linux_abort(Scsi_Cmnd *cmd)
int found;
#endif
- ahd = *(struct ahd_softc **)cmd->host->hostdata;
+ ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
#if NOTYET
int error;
@@ -1251,7 +1251,7 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd)
int found;
#endif
- ahd = *(struct ahd_softc **)cmd->host->hostdata;
+ ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
printf("%s: Dev reset called for cmd %p\n",
@@ -1283,14 +1283,14 @@ ahd_linux_bus_reset(Scsi_Cmnd *cmd)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_unlock_irq(&io_request_lock);
#endif
- ahd = *(struct ahd_softc **)cmd->host->hostdata;
+ ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
#ifdef AHD_DEBUG
if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
printf("%s: Bus reset called for cmd %p\n",
ahd_name(ahd), cmd);
#endif
ahd_midlayer_entrypoint_lock(ahd, &s);
- found = ahd_reset_channel(ahd, cmd->channel + 'A',
+ found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
/*initiate reset*/TRUE);
acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
TAILQ_INIT(&ahd->platform_data->completeq);
@@ -1415,7 +1415,7 @@ static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf)
/******************************** Macros **************************************/
#define BUILD_SCSIID(ahd, cmd) \
- ((((cmd)->target << TID_SHIFT) & TID) | (ahd)->our_id)
+ ((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id)
/******************************** Bus DMA *************************************/
int
@@ -3687,7 +3687,7 @@ ahd_linux_dv_timeout(struct scsi_cmnd *cmd)
struct scb *scb;
u_long flags;
- ahd = *((struct ahd_softc **)cmd->host->hostdata);
+ ahd = *((struct ahd_softc **)cmd->device->host->hostdata);
ahd_lock(ahd, &flags);
#ifdef AHD_DEBUG
@@ -3715,7 +3715,7 @@ ahd_linux_dv_timeout(struct scsi_cmnd *cmd)
ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
else
ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
- ahd_reset_channel(ahd, cmd->channel + 'A', /*initiate*/TRUE);
+ ahd_reset_channel(ahd, cmd->device->channel + 'A', /*initiate*/TRUE);
/*
* Add a minimal bus settle delay for devices that are slow to
@@ -3765,7 +3765,7 @@ ahd_linux_dv_complete(struct scsi_cmnd *cmd)
{
struct ahd_softc *ahd;
- ahd = *((struct ahd_softc **)cmd->host->hostdata);
+ ahd = *((struct ahd_softc **)cmd->device->host->hostdata);
/* Delete the DV timer before it goes off! */
scsi_delete_timer(cmd);
@@ -3773,7 +3773,8 @@ ahd_linux_dv_complete(struct scsi_cmnd *cmd)
#ifdef AHD_DEBUG
if (ahd_debug & AHD_SHOW_DV)
printf("%s:%c:%d: Command completed, status= 0x%x\n",
- ahd_name(ahd), cmd->channel, cmd->target, cmd->result);
+ ahd_name(ahd), cmd->device->channel,
+ cmd->device->id, cmd->result);
#endif
/* Wake up the state machine */
@@ -3967,12 +3968,13 @@ ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev)
* Get an scb to use.
*/
tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
- cmd->target, &tstate);
+ cmd->device->id, &tstate);
if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0
|| (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
col_idx = AHD_NEVER_COL_IDX;
} else {
- col_idx = AHD_BUILD_COL_IDX(cmd->target, cmd->lun);
+ col_idx = AHD_BUILD_COL_IDX(cmd->device->id,
+ cmd->device->lun);
}
if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq,
@@ -3992,7 +3994,7 @@ ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev)
*/
hscb->control = 0;
hscb->scsiid = BUILD_SCSIID(ahd, cmd);
- hscb->lun = cmd->lun;
+ hscb->lun = cmd->device->lun;
mask = SCB_GET_TARGET_MASK(ahd, scb);
if ((ahd->user_discenable & mask) != 0)
@@ -4660,8 +4662,9 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd)
struct ahd_devinfo devinfo;
uint32_t action;
- dev = ahd_linux_get_device(ahd, cmd->channel,
- cmd->target, cmd->lun,
+ dev = ahd_linux_get_device(ahd, cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun,
/*alloc*/FALSE);
if (dev == NULL)
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 07087d348cd6..525247958312 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -976,7 +976,7 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
struct ahc_linux_device *dev;
u_long flags;
- ahc = *(struct ahc_softc **)cmd->host->hostdata;
+ ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
/*
* Save the callback on completion function.
@@ -1000,8 +1000,8 @@ ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
ahc_midlayer_entrypoint_unlock(ahc, &flags);
return (0);
}
- dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target,
- cmd->lun, /*alloc*/TRUE);
+ dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
+ cmd->device->lun, /*alloc*/TRUE);
if (dev == NULL) {
ahc_midlayer_entrypoint_unlock(ahc, &flags);
printf("aic7xxx_linux_queue: Unable to allocate device!\n");
@@ -1245,12 +1245,12 @@ ahc_linux_bus_reset(Scsi_Cmnd *cmd)
u_long s;
int found;
- ahc = *(struct ahc_softc **)cmd->host->hostdata;
+ ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
spin_unlock_irq(&io_request_lock);
#endif
ahc_midlayer_entrypoint_lock(ahc, &s);
- found = ahc_reset_channel(ahc, cmd->channel + 'A',
+ found = ahc_reset_channel(ahc, cmd->device->channel + 'A',
/*initiate reset*/TRUE);
acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
TAILQ_INIT(&ahc->platform_data->completeq);
@@ -1374,10 +1374,10 @@ static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf)
}
/******************************** Macros **************************************/
-#define BUILD_SCSIID(ahc, cmd) \
- ((((cmd)->target << TID_SHIFT) & TID) \
- | (((cmd)->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \
- | (((cmd)->channel == 0) ? 0 : TWIN_CHNLB))
+#define BUILD_SCSIID(ahc, cmd) \
+ ((((cmd)->device->id << TID_SHIFT) & TID) \
+ | (((cmd)->device->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b)\
+ | (((cmd)->device->channel == 0) ? 0 : TWIN_CHNLB))
/******************************** Bus DMA *************************************/
int
@@ -3532,7 +3532,7 @@ ahc_linux_dv_timeout(struct scsi_cmnd *cmd)
struct scb *scb;
u_long flags;
- ahc = *((struct ahc_softc **)cmd->host->hostdata);
+ ahc = *((struct ahc_softc **)cmd->device->host->hostdata);
ahc_lock(ahc, &flags);
#ifdef AHC_DEBUG
@@ -3560,7 +3560,7 @@ ahc_linux_dv_timeout(struct scsi_cmnd *cmd)
ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
else
ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT);
- ahc_reset_channel(ahc, cmd->channel + 'A', /*initiate*/TRUE);
+ ahc_reset_channel(ahc, cmd->device->channel + 'A', /*initiate*/TRUE);
/*
* Add a minimal bus settle delay for devices that are slow to
@@ -3610,7 +3610,7 @@ ahc_linux_dv_complete(struct scsi_cmnd *cmd)
{
struct ahc_softc *ahc;
- ahc = *((struct ahc_softc **)cmd->host->hostdata);
+ ahc = *((struct ahc_softc **)cmd->device->host->hostdata);
/* Delete the DV timer before it goes off! */
scsi_delete_timer(cmd);
@@ -3618,7 +3618,8 @@ ahc_linux_dv_complete(struct scsi_cmnd *cmd)
#ifdef AHC_DEBUG
if (ahc_debug & AHC_SHOW_DV)
printf("%s:%d:%d: Command completed, status= 0x%x\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->result);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id,
+ cmd->result);
#endif
/* Wake up the state machine */
@@ -3834,7 +3835,7 @@ ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
*/
hscb->control = 0;
hscb->scsiid = BUILD_SCSIID(ahc, cmd);
- hscb->lun = cmd->lun;
+ hscb->lun = cmd->device->lun;
mask = SCB_GET_TARGET_MASK(ahc, scb);
tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb),
SCB_GET_OUR_ID(scb),
@@ -4859,11 +4860,12 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
pending_scb = NULL;
paused = FALSE;
wait = FALSE;
- ahc = *(struct ahc_softc **)cmd->host->hostdata;
+ ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
acmd = (struct ahc_cmd *)cmd;
printf("%s:%d:%d:%d: Attempting to queue a%s message\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun,
+ ahc_name(ahc), cmd->device->channel, cmd->device->id,
+ cmd->device->lun,
flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
/*
@@ -4892,8 +4894,8 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
* at all, and the system wanted us to just abort the
* command return success.
*/
- dev = ahc_linux_get_device(ahc, cmd->channel, cmd->target,
- cmd->lun, /*alloc*/FALSE);
+ dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
+ cmd->device->lun, /*alloc*/FALSE);
if (dev == NULL) {
/*
@@ -4901,7 +4903,8 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
* so we must not still own the command.
*/
printf("%s:%d:%d:%d: Is not an active device\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id,
+ cmd->device->lun);
retval = SUCCESS;
goto no_cmd;
}
@@ -4913,7 +4916,8 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
if (list_acmd != NULL) {
printf("%s:%d:%d:%d: Command found on device queue\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id,
+ cmd->device->lun);
if (flag == SCB_ABORT) {
TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
cmd->result = DID_ABORT << 16;
@@ -4924,11 +4928,13 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
}
if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0
- && ahc_search_untagged_queues(ahc, cmd, cmd->target,
- cmd->channel + 'A', cmd->lun,
+ && ahc_search_untagged_queues(ahc, cmd, cmd->device->id,
+ cmd->device->channel + 'A',
+ cmd->device->lun,
CAM_REQ_ABORTED, SEARCH_COMPLETE) != 0) {
printf("%s:%d:%d:%d: Command found on untagged queue\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id,
+ cmd->device->lun);
retval = SUCCESS;
goto done;
}
@@ -4945,8 +4951,9 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
/* Any SCB for this device will do for a target reset */
LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {
- if (ahc_match_scb(ahc, pending_scb, cmd->target,
- cmd->channel + 'A', CAM_LUN_WILDCARD,
+ if (ahc_match_scb(ahc, pending_scb, cmd->device->id,
+ cmd->device->channel + 'A',
+ CAM_LUN_WILDCARD,
SCB_LIST_NULL, ROLE_INITIATOR) == 0)
break;
}
@@ -4954,7 +4961,8 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
if (pending_scb == NULL) {
printf("%s:%d:%d:%d: Command not found\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id,
+ cmd->device->lun);
goto no_cmd;
}
@@ -4978,24 +4986,24 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
if ((pending_scb->flags & SCB_ACTIVE) == 0) {
printf("%s:%d:%d:%d: Command already completed\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id, cmd->device->lun);
goto no_cmd;
}
disconnected = TRUE;
if (flag == SCB_ABORT) {
- if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A',
- cmd->lun, pending_scb->hscb->tag,
+ if (ahc_search_qinfifo(ahc, cmd->device->id, cmd->device->channel + 'A',
+ cmd->device->lun, pending_scb->hscb->tag,
ROLE_INITIATOR, CAM_REQ_ABORTED,
SEARCH_COMPLETE) > 0) {
printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
- ahc_name(ahc), cmd->channel, cmd->target,
- cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id,
+ cmd->device->lun);
retval = SUCCESS;
goto done;
}
- } else if (ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A',
- cmd->lun, pending_scb->hscb->tag,
+ } else if (ahc_search_qinfifo(ahc, cmd->device->id, cmd->device->channel + 'A',
+ cmd->device->lun, pending_scb->hscb->tag,
ROLE_INITIATOR, /*status*/0,
SEARCH_COUNT) > 0) {
disconnected = FALSE;
@@ -5027,7 +5035,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
if (last_phase != P_BUSFREE
&& (pending_scb->hscb->tag == active_scb_index
|| (flag == SCB_DEVICE_RESET
- && SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)) == cmd->target))) {
+ && SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)) == cmd->device->id))) {
/*
* We're active on the bus, so assert ATN
@@ -5038,7 +5046,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
ahc_outb(ahc, MSG_OUT, HOST_MSG);
ahc_outb(ahc, SCSISIGO, last_phase|ATNO);
printf("%s:%d:%d:%d: Device is active, asserting ATN\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id, cmd->device->lun);
wait = TRUE;
} else if (disconnected) {
@@ -5068,8 +5076,8 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
* same element in the SCB, SCB_NEXT, for
* both the qinfifo and the disconnected list.
*/
- ahc_search_disc_list(ahc, cmd->target, cmd->channel + 'A',
- cmd->lun, pending_scb->hscb->tag,
+ ahc_search_disc_list(ahc, cmd->device->id, cmd->device->channel + 'A',
+ cmd->device->lun, pending_scb->hscb->tag,
/*stop_on_first*/TRUE,
/*remove*/TRUE,
/*save_state*/FALSE);
@@ -5092,19 +5100,19 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
* so we are the next SCB for this target
* to run.
*/
- ahc_search_qinfifo(ahc, cmd->target, cmd->channel + 'A',
- cmd->lun, SCB_LIST_NULL, ROLE_INITIATOR,
+ ahc_search_qinfifo(ahc, cmd->device->id, cmd->device->channel + 'A',
+ cmd->device->lun, SCB_LIST_NULL, ROLE_INITIATOR,
CAM_REQUEUE_REQ, SEARCH_COMPLETE);
ahc_print_path(ahc, pending_scb);
printf("Queuing a recovery SCB\n");
ahc_qinfifo_requeue_tail(ahc, pending_scb);
ahc_outb(ahc, SCBPTR, saved_scbptr);
printf("%s:%d:%d:%d: Device is disconnected, re-queuing SCB\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id, cmd->device->lun);
wait = TRUE;
} else {
printf("%s:%d:%d:%d: Unable to deliver message\n",
- ahc_name(ahc), cmd->channel, cmd->target, cmd->lun);
+ ahc_name(ahc), cmd->device->channel, cmd->device->id, cmd->device->lun);
retval = FAILED;
goto done;
}
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
index 5d5b712a3dc3..843ead6b75cf 100644
--- a/drivers/scsi/cpqfcTSinit.c
+++ b/drivers/scsi/cpqfcTSinit.c
@@ -1604,8 +1604,7 @@ return -ENOTSUPP;
scsi_cdb[0] = RELEASE;
- // allocate with wait = true, interruptible = false
- SCpnt = scsi_allocate_device(ScsiDev, 1);
+ SCpnt = scsi_getset_command(ScsiDev, GFP_KERNEL);
{
CPQFC_DECLARE_COMPLETION(wait);
@@ -1654,7 +1653,7 @@ return -ENOTSUPP;
result = SCpnt->result;
SDpnt = SCpnt->device;
- scsi_release_command(SCpnt);
+ scsi_put_command(SCpnt);
SCpnt = NULL;
// if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index d845a915a292..3c3135c3bcdf 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -4637,7 +4637,7 @@ static void gdth_flush(int hanum)
#if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
- scp = scsi_allocate_device(sdev, 1);
+ scp = scsi_getset_command(sdev, GFP_KERNEL);
scp->cmd_len = 12;
scp->use_sg = 0;
#else
@@ -4665,7 +4665,7 @@ static void gdth_flush(int hanum)
}
}
#if LINUX_VERSION_CODE >= 0x020322
- scsi_release_command(scp);
+ scsi_put_command(scp);
scsi_free_host_dev(sdev);
#endif
}
@@ -4711,7 +4711,7 @@ void gdth_halt(void)
memset(cmnd, 0xff, MAX_COMMAND_SIZE);
#if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
- scp = scsi_allocate_device(sdev, 1);
+ scp = scsi_getset_command(sdev, GFP_KERNEL);
scp->cmd_len = 12;
scp->use_sg = 0;
#else
@@ -4728,7 +4728,7 @@ void gdth_halt(void)
TRACE2(("gdth_halt(): reset controller %d\n", hanum));
#if LINUX_VERSION_CODE >= 0x020322
gdth_do_cmd(scp, &gdtcmd, cmnd, 10);
- scsi_release_command(scp);
+ scsi_put_command(scp);
scsi_free_host_dev(sdev);
#else
gdth_do_cmd(&scp, &gdtcmd, cmnd, 10);
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index f9facb7bbbd2..9b943a37ce0e 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -48,7 +48,7 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
#if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
- scp = scsi_allocate_device(sdev, 1);
+ scp = scsi_getset_command(sdev, GFP_KERNEL);
if (!scp)
return -ENOMEM;
scp->cmd_len = 12;
@@ -81,7 +81,7 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
ret_val = -EINVAL;
}
#if LINUX_VERSION_CODE >= 0x020322
- scsi_release_command(scp);
+ scsi_put_command(scp);
scsi_free_host_dev(sdev);
#endif
return ret_val;
@@ -712,7 +712,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
#if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
- scp = scsi_allocate_device(sdev, 1);
+ scp = scsi_getset_command(sdev, GFP_KERNEL);
if (!scp)
return -ENOMEM;
scp->cmd_len = 12;
@@ -1234,7 +1234,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
stop_output:
#if LINUX_VERSION_CODE >= 0x020322
- scsi_release_command(scp);
+ scsi_put_command(scp);
scsi_free_host_dev(sdev);
#endif
*start = buffer +(offset-begin);
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 94ffaf8540ca..6ca0adf6706d 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -350,6 +350,13 @@ void scsi_unregister(struct Scsi_Host *shost)
/* Cleanup proc */
scsi_proc_host_rm(shost);
+ while (!list_empty(&shost->free_list)) {
+ struct scsi_cmnd *cmd;
+ cmd = list_entry(shost->free_list.next,struct scsi_cmnd,list);
+ list_del_init(&cmd->list);
+ kmem_cache_free(scsi_core->scsi_cmd_cache, cmd);
+ }
+
kfree(shost);
}
@@ -370,6 +377,7 @@ extern int blk_nohighio;
struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
{
struct Scsi_Host *shost, *shost_scr;
+ struct scsi_cmnd *cmd = NULL;
int gfp_mask;
DECLARE_COMPLETION(sem);
@@ -459,6 +467,16 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
found:
spin_unlock(&scsi_host_list_lock);
+ spin_lock_init(&shost->free_list_lock);
+ INIT_LIST_HEAD(&shost->free_list);
+
+ /* Get one backup command for this host. */
+ cmd = scsi_get_command(shost, GFP_KERNEL);
+ if (cmd)
+ list_add(&cmd->list, &shost->free_list);
+ else
+ printk(KERN_NOTICE "The system is running low in memory.\n");
+
scsi_proc_host_add(shost);
shost->eh_notify = &sem;
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index f0f607862cb8..cf2a58ba50ce 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -375,6 +375,9 @@ struct Scsi_Host
struct list_head sh_list;
struct list_head my_devices;
+ spinlock_t free_list_lock;
+ struct list_head free_list; /* backup store of cmd structs */
+
spinlock_t default_lock;
spinlock_t *host_lock;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index d17729524a7a..ef553600e24f 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -265,7 +265,7 @@ void scsi_release_request(Scsi_Request * req)
{
if( req->sr_command != NULL )
{
- scsi_release_command(req->sr_command);
+ scsi_put_command(req->sr_command);
req->sr_command = NULL;
}
@@ -768,7 +768,7 @@ void scsi_wait_req (Scsi_Request * SRpnt, const void *cmnd ,
SRpnt->sr_request->waiting = NULL;
if( SRpnt->sr_command != NULL )
{
- scsi_release_command(SRpnt->sr_command);
+ scsi_put_command(SRpnt->sr_command);
SRpnt->sr_command = NULL;
}
@@ -834,7 +834,7 @@ void scsi_do_req(Scsi_Request * SRpnt, const void *cmnd,
*/
if( SRpnt->sr_command != NULL )
{
- scsi_release_command(SRpnt->sr_command);
+ scsi_put_command(SRpnt->sr_command);
SRpnt->sr_command = NULL;
}
@@ -1506,6 +1506,12 @@ void scsi_adjust_queue_depth(Scsi_Device *SDpnt, int tagged, int tags)
SDpnt->new_queue_depth = tags;
break;
}
+ /* TODO FIXME This is a hack and MUST go eventually.
+ This fixes a problem in scsi_scan.c::scsi_alloc_sdev()
+ else we cannot ever have ANY SCSI devices.
+ */
+ SDpnt->current_queue_depth = 1;
+
spin_unlock_irqrestore(&device_request_lock, flags);
}
@@ -2017,6 +2023,14 @@ static int __init init_scsi(void)
{
printk(KERN_INFO "SCSI subsystem driver " REVISION "\n");
+ scsi_core = kmalloc(sizeof(*scsi_core), GFP_KERNEL);
+ if (!scsi_core)
+ goto out_no_mem;
+ memset(scsi_core, 0, sizeof(*scsi_core));
+
+ if (scsi_create_cmdcache(scsi_core))
+ goto out_no_mem;
+
scsi_init_queue();
scsi_init_procfs();
devfs_mk_dir(NULL, "scsi", NULL);
@@ -2025,6 +2039,10 @@ static int __init init_scsi(void)
scsi_sysfs_register();
open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
return 0;
+
+out_no_mem:
+ printk(KERN_CRIT "Couldn't load SCSI Core -- out of memory!\n");
+ return -ENOMEM;
}
static void __exit exit_scsi(void)
@@ -2034,6 +2052,12 @@ static void __exit exit_scsi(void)
devfs_remove("scsi");
scsi_exit_procfs();
scsi_exit_queue();
+
+ scsi_destroy_cmdcache(scsi_core);
+
+ if (scsi_core)
+ kfree(scsi_core);
+ scsi_core = NULL;
}
subsys_initcall(init_scsi);
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index 1922388b07aa..0e47f156821e 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -734,7 +734,8 @@ struct scsi_cmnd {
Scsi_Request *sc_request;
struct scsi_cmnd *next;
struct scsi_cmnd *reset_chain;
- struct list_head list_entry; /* Used to place us on the cmd lists */
+
+ struct list_head list; /* scsi_cmnd participates in queue lists */
int eh_state; /* Used for state tracking in error handlr */
int eh_eflags; /* Used by error handlr */
@@ -994,4 +995,45 @@ extern void scsi_device_unregister(struct scsi_device *);
extern int scsi_sysfs_register(void);
extern void scsi_sysfs_unregister(void);
+/* -------------------------------------------------- */
+/* data decl: */
+
+/* All the SCSI Core specific global data, etc,
+ should go in here.
+*/
+
+struct scsi_core_data {
+ kmem_cache_t *scsi_cmd_cache;
+ kmem_cache_t *scsi_cmd_dma_cache;
+};
+
+extern struct scsi_core_data *scsi_core;
+
+/* -------------------------------------------------- */
+/* fn decl: */
+
+int scsi_create_cmdcache(struct scsi_core_data *scsi_core);
+int scsi_destroy_cmdcache(struct scsi_core_data *scsi_core);
+
+struct scsi_cmnd * scsi_get_command(struct Scsi_Host *host, int alloc_flags);
+void scsi_put_command(struct scsi_cmnd *cmd);
+void scsi_setup_command(struct scsi_device *dev, struct scsi_cmnd *cmd);
+
+/* -------------------------------------------------- */
+/* inline funcs: */
+
+/* scsi_getset_command: allocate, set and return a command struct,
+ when the device is known.
+*/
+static inline struct scsi_cmnd *scsi_getset_command(struct scsi_device *dev,
+ int flags)
+{
+ struct scsi_cmnd *cmd;
+
+ if (!dev) return NULL;
+ if (!dev->host) return NULL;
+ scsi_setup_command(dev, (cmd = scsi_get_command(dev->host, flags)));
+ return cmd;
+}
+
#endif
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 4860191c5c87..bef0602ef98a 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -1371,7 +1371,7 @@ static void scsi_eh_lock_done(struct scsi_cmnd *scmd)
scmd->sc_request = NULL;
sreq->sr_command = NULL;
- scsi_release_command(scmd);
+ scsi_put_command(scmd);
scsi_release_request(sreq);
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index eedbde292d6a..7e2e6385d885 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -33,7 +33,9 @@ struct scsi_host_sg_pool {
struct scsi_host_sg_pool scsi_sg_pools[SG_MEMPOOL_NR] = {
SP(8), SP(16), SP(32), SP(64), SP(MAX_PHYS_SEGMENTS)
};
-#undef SP
+#undef SP
+
+struct scsi_core_data *scsi_core;
/*
* Function: scsi_insert_special_cmd()
@@ -357,7 +359,7 @@ static Scsi_Cmnd *scsi_end_request(Scsi_Cmnd * SCpnt,
* This will goose the queue request function at the end, so we don't
* need to worry about launching another command.
*/
- __scsi_release_command(SCpnt);
+ scsi_put_command(SCpnt);
scsi_queue_next_request(q, NULL);
return NULL;
}
@@ -816,7 +818,8 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
SRpnt = (Scsi_Request *) req->special;
if( SRpnt->sr_magic == SCSI_REQ_MAGIC ) {
- SCpnt = scsi_allocate_device(SRpnt->sr_device, 0);
+ SCpnt = scsi_getset_command(SRpnt->sr_device,
+ GFP_ATOMIC);
if (!SCpnt)
return BLKPREP_DEFER;
scsi_init_cmd_from_req(SCpnt, SRpnt);
@@ -829,7 +832,7 @@ int scsi_prep_fn(struct request_queue *q, struct request *req)
if (req->special) {
SCpnt = (Scsi_Cmnd *) req->special;
} else {
- SCpnt = scsi_allocate_device(SDpnt, 0);
+ SCpnt = scsi_getset_command(SDpnt, GFP_ATOMIC);
}
/*
* if command allocation failure, wait a bit
@@ -1193,3 +1196,143 @@ void __exit scsi_exit_queue(void)
kmem_cache_destroy(sgp->slab);
}
}
+
+/* -------------------------------------------------- */
+
+int scsi_create_cmdcache(struct scsi_core_data *scsi_core)
+{
+ if (!scsi_core)
+ return -EFAULT;
+
+ scsi_core->scsi_cmd_cache
+ = kmem_cache_create("scsi_cmd_cache",
+ sizeof(struct scsi_cmnd), 0,
+ SLAB_NO_REAP|SLAB_HWCACHE_ALIGN,NULL,NULL);
+ if (!scsi_core->scsi_cmd_cache)
+ return -ENOMEM;
+
+ scsi_core->scsi_cmd_dma_cache
+ = kmem_cache_create("scsi_cmd_cache(DMA)",
+ sizeof(struct scsi_cmnd), 0,
+ SLAB_NO_REAP|SLAB_HWCACHE_ALIGN
+ |SLAB_CACHE_DMA,
+ NULL,NULL);
+ if (!scsi_core->scsi_cmd_dma_cache) {
+ scsi_destroy_cmdcache(scsi_core);
+ return -ENOMEM;
+ }
+ return 0;
+} /* end scsi_create_cmdcache() */
+
+/* -------------------------------------------------- */
+
+int scsi_destroy_cmdcache(struct scsi_core_data *scsi_core)
+{
+ if (!scsi_core)
+ return -EFAULT;
+
+ if (scsi_core->scsi_cmd_cache &&
+ kmem_cache_destroy(scsi_core->scsi_cmd_cache)) {
+ goto bail;
+ } else {
+ scsi_core->scsi_cmd_cache = NULL;
+ }
+
+ if (scsi_core->scsi_cmd_dma_cache &&
+ kmem_cache_destroy(scsi_core->scsi_cmd_dma_cache)) {
+ goto bail;
+ } else {
+ scsi_core->scsi_cmd_dma_cache = NULL;
+ }
+
+ return 0;
+bail:
+ printk(KERN_CRIT "Failed to free scsi command cache"
+ " -- memory leak\n");
+ return -EFAULT;
+} /* end scsi_destroy_cmdcache() */
+
+/* -------------------------------------------------- */
+
+struct scsi_cmnd * scsi_get_command(struct Scsi_Host *host, int alloc_flags)
+{
+ unsigned long flags;
+ struct scsi_cmnd *cmd = NULL;
+
+ if (!host)
+ return NULL;
+
+ if (host->unchecked_isa_dma) {
+ cmd = kmem_cache_alloc(scsi_core->scsi_cmd_dma_cache,
+ alloc_flags);
+ } else {
+ cmd = kmem_cache_alloc(scsi_core->scsi_cmd_cache, alloc_flags);
+ }
+
+ if (!cmd) {
+ spin_lock_irqsave(&host->free_list_lock, flags);
+ if (!list_empty(&host->free_list)) {
+ cmd = list_entry(host->free_list.next,
+ struct scsi_cmnd, list);
+ list_del_init(&cmd->list);
+ }
+ spin_unlock_irqrestore(&host->free_list_lock, flags);
+ }
+
+ return cmd;
+} /* end scsi_get_command() */
+
+/* -------------------------------------------------- */
+/* scsi_put_command: free a scsi_cmnd struct.
+ Note: the command must not belong to any lists!
+*/
+void scsi_put_command(struct scsi_cmnd *cmd)
+{
+ unsigned long flags;
+ struct Scsi_Host *host;
+
+ if (!cmd)
+ return;
+
+ if (!cmd->device || !cmd->device->host) {
+ printk(KERN_NOTICE "Trying to free a command which"
+ " doesn't belong to scsi core?!\n");
+ /* Memory leak, but let the system survive for now --
+ they'll get it eventually! */
+ return;
+ }
+
+ host = cmd->device->host;
+
+ spin_lock_irqsave(&host->free_list_lock, flags);
+ if (list_empty(&host->free_list)) {
+ list_add(&cmd->list, &host->free_list);
+ cmd = NULL;
+ }
+ spin_unlock_irqrestore(&host->free_list_lock, flags);
+
+ if (cmd) {
+ if (host->unchecked_isa_dma)
+ kmem_cache_free(scsi_core->scsi_cmd_dma_cache, cmd);
+ else
+ kmem_cache_free(scsi_core->scsi_cmd_cache, cmd);
+ }
+} /* end scsi_put_command() */
+
+/* -------------------------------------------------- */
+/* scsi_setup_command: This will do post-alloc init of the command.
+ We want to do as little as possible here.
+*/
+void scsi_setup_command(struct scsi_device *dev, struct scsi_cmnd *cmd)
+{
+ if (!cmd)
+ return;
+ memset(cmd, 0, sizeof(*cmd));
+ cmd->device = dev;
+ cmd->state = SCSI_STATE_UNUSED;
+ cmd->owner = SCSI_OWNER_NOBODY;
+ init_timer(&cmd->eh_timeout);
+ INIT_LIST_HEAD(&cmd->list);
+} /* end scsi_setup_command() */
+
+/* -------------------------------------------------- */
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index bf7d388a0b3b..ea5ab1d4d900 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -471,7 +471,6 @@ static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
sdev->request_queue->queuedata = sdev;
scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
- scsi_build_commandblocks(sdev);
if (sdev->current_queue_depth == 0) {
goto out_bail;
}
@@ -515,7 +514,6 @@ out_bail:
} else if (sdev->request_queue)
scsi_free_queue(sdev->request_queue);
- scsi_release_commandblocks(sdev);
kfree(sdev);
return NULL;
}
@@ -535,7 +533,6 @@ static void scsi_free_sdev(struct scsi_device *sdev)
if (sdev->request_queue)
scsi_free_queue(sdev->request_queue);
- scsi_release_commandblocks(sdev);
if (sdev->host->hostt->slave_destroy)
sdev->host->hostt->slave_destroy(sdev);
if (sdev->inquiry)
diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
index c3f938e2a99c..1b2ee3cb436b 100644
--- a/drivers/scsi/scsi_syms.c
+++ b/drivers/scsi/scsi_syms.c
@@ -39,7 +39,6 @@ EXPORT_SYMBOL(scsi_unregister);
EXPORT_SYMBOL(scsicam_bios_param);
EXPORT_SYMBOL(scsi_partsize);
EXPORT_SYMBOL(scsi_bios_ptable);
-EXPORT_SYMBOL(scsi_allocate_device);
EXPORT_SYMBOL(scsi_do_cmd);
EXPORT_SYMBOL(scsi_ioctl);
EXPORT_SYMBOL(print_command);
@@ -50,7 +49,6 @@ EXPORT_SYMBOL(print_status);
EXPORT_SYMBOL(scsi_sense_key_string);
EXPORT_SYMBOL(scsi_extd_sense_format);
EXPORT_SYMBOL(kernel_scsi_ioctl);
-EXPORT_SYMBOL(scsi_release_command);
EXPORT_SYMBOL(print_Scsi_Cmnd);
EXPORT_SYMBOL(scsi_block_when_processing_errors);
EXPORT_SYMBOL(scsi_ioctl_send_command);
@@ -114,3 +112,8 @@ EXPORT_SYMBOL(scsi_delete_timer);
* sysfs support
*/
EXPORT_SYMBOL(shost_devclass);
+
+EXPORT_SYMBOL(scsi_get_command);
+EXPORT_SYMBOL(scsi_put_command);
+EXPORT_SYMBOL(scsi_setup_command);
+