Commit bede2c88 authored by James Bottomley's avatar James Bottomley

Merge raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5

into raven.il.steeleye.com:/home/jejb/BK/scsi-for-linus-2.6
parents db82f17d 4277ddc2
......@@ -60,6 +60,7 @@
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/list.h>
/*---------------------------------------------------------------------------
Features
......@@ -306,7 +307,7 @@ struct NvRamType {
SCSI Request Block
-----------------------------------------------------------------------*/
struct ScsiReqBlk {
struct ScsiReqBlk *next;
struct list_head list; /* next/prev ptrs for srb lists */
struct DeviceCtlBlk *dcb;
/* HW scatter list (up to 64 entries) */
......@@ -350,22 +351,16 @@ struct ScsiReqBlk {
Device Control Block
-----------------------------------------------------------------------*/
struct DeviceCtlBlk {
struct DeviceCtlBlk *next;
struct list_head list; /* next/prev ptrs for the dcb list */
struct AdapterCtlBlk *acb;
struct ScsiReqBlk *going_srb;
struct ScsiReqBlk *going_last;
struct ScsiReqBlk *waiting_srb;
struct ScsiReqBlk *wait_list;
struct list_head srb_going_list; /* head of going srb list */
struct list_head srb_waiting_list; /* head of waiting srb list */
struct ScsiReqBlk *active_srb;
u32 tag_mask;
u16 max_command;
u16 going_srb_count;
u16 waiting_srb_count;
u8 target_id; /* SCSI Target ID (SCSI Only) */
u8 target_lun; /* SCSI Log. Unit (SCSI Only) */
u8 identify_msg;
......@@ -390,20 +385,17 @@ struct AdapterCtlBlk {
u16 IOPortBase;
struct DeviceCtlBlk *link_dcb;
struct DeviceCtlBlk *last_dcb;
struct list_head dcb_list; /* head of going dcb list */
struct DeviceCtlBlk *dcb_run_robin;
struct DeviceCtlBlk *active_dcb;
struct ScsiReqBlk *free_srb;
struct list_head srb_free_list; /* head of free srb list */
struct ScsiReqBlk *tmp_srb;
struct timer_list waiting_timer;
struct timer_list selto_timer;
u16 srb_count;
u8 dcb_count;
u8 sel_timeout;
u8 irq_level;
......@@ -824,6 +816,60 @@ void __init eeprom_override(struct NvRamType *eeprom)
/*---------------------------------------------------------------------------
---------------------------------------------------------------------------*/
/**
* list_size - Returns the size (in number of entries) of the
* supplied list.
*
* @head: The pointer to the head of the list to count the items in.
**/
unsigned int list_size(struct list_head *head)
{
unsigned int count = 0;
struct list_head *pos;
list_for_each(pos, head)
count++;
return count;
}
/**
* dcb_get_next - Given a dcb return the next dcb in the list of
* dcb's, wrapping back to the start of the dcb list if required.
* Returns the supplied dcb if there is only one dcb in the list.
*
* @head: The pointer to the head of the list to count the items in.
* @pos: The pointer the dcb for which we are searching for the
* following dcb.
**/
struct DeviceCtlBlk *dcb_get_next(
struct list_head *head,
struct DeviceCtlBlk *pos)
{
int use_next = 0;
struct DeviceCtlBlk* next = NULL;
struct DeviceCtlBlk* i;
if (list_empty(head))
return NULL;
/* find supplied dcb and then select the next one */
list_for_each_entry(i, head, list)
if (use_next) {
next = i;
break;
} else if (i == pos) {
use_next = 1;
}
/* if no next one take the head one (ie, wraparound) */
if (!next)
list_for_each_entry(i, head, list) {
next = i;
break;
}
return next;
}
/*
* Queueing philosphy:
......@@ -851,200 +897,153 @@ void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
/* Find cmd in SRB list */
inline static
struct ScsiReqBlk *find_cmd(Scsi_Cmnd * cmd,
struct ScsiReqBlk *start)
struct ScsiReqBlk *find_cmd(Scsi_Cmnd *cmd,
struct list_head *head)
{
struct ScsiReqBlk *psrb = start;
if (!start)
return 0;
do {
if (psrb->cmd == cmd)
return psrb;
psrb = psrb->next;
} while (psrb && psrb != start);
return 0;
struct ScsiReqBlk *i;
list_for_each_entry(i, head, list)
if (i->cmd == cmd)
return i;
return NULL;
}
/* Return next free SRB */
static inline
struct ScsiReqBlk *get_srb_free(struct AdapterCtlBlk *acb)
/*
* srb_get_free - Return a free srb from the list of free SRBs that
* is stored with the acb.
*/
static
struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb)
{
struct list_head *head = &acb->srb_free_list;
struct ScsiReqBlk *srb;
/*DC395x_Free_integrity (acb); */
srb = acb->free_srb;
if (!srb)
if (!list_empty(head)) {
srb = list_entry(head->next, struct ScsiReqBlk, list);
list_del(head->next);
dprintkdbg(DBG_0, "srb_get_free: got srb %p\n", srb);
} else {
srb = NULL;
dprintkl(KERN_ERR, "Out of Free SRBs :-(\n");
if (srb) {
acb->free_srb = srb->next;
srb->next = NULL;
}
return srb;
}
/* Insert SRB oin top of free list */
static inline
void insert_srb_free(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
/*
* srb_free_insert - Insert an srb to the head of the free list
* stored in the acb.
*/
static
void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "Free SRB %p\n", srb);
srb->next = acb->free_srb;
acb->free_srb = srb;
dprintkdbg(DBG_0, "srb_free_insert: put srb %p\n", srb);
list_add_tail(&srb->list, &acb->srb_free_list);
}
/* Inserts a SRB to the top of the Waiting list */
static inline
void insert_srb_waiting(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
/*
* srb_waiting_insert - Insert an srb to the head of the wiating list
* stored in the dcb.
*/
static
void srb_waiting_insert(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "Insert srb %p cmd %li to Waiting\n", srb, srb->cmd->pid);
srb->next = dcb->waiting_srb;
if (!dcb->waiting_srb)
dcb->wait_list = srb;
dcb->waiting_srb = srb;
dcb->waiting_srb_count++;
dprintkdbg(DBG_0, "srb_waiting_insert: srb %p cmd %li\n", srb, srb->cmd->pid);
list_add(&srb->list, &dcb->srb_waiting_list);
}
/* Queue SRB to waiting list */
/*
* srb_waiting_append - Append an srb to the tail of the waiting list
* stored in the dcb.
*/
static inline
void append_srb_waiting(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
void srb_waiting_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "Append srb %p cmd %li to Waiting\n", srb, srb->cmd->pid);
if (dcb->waiting_srb)
dcb->wait_list->next = srb;
else
dcb->waiting_srb = srb;
dcb->wait_list = srb;
/* No next one in waiting list */
srb->next = NULL;
dcb->waiting_srb_count++;
dprintkdbg(DBG_0, "srb_waiting_append: srb %p cmd %li\n", srb, srb->cmd->pid);
list_add_tail(&srb->list, &dcb->srb_waiting_list);
}
/*
* srb_going_append - Append an srb to the tail of the going list
* stored in the dcb.
*/
static inline
void append_srb_going(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "Append SRB %p to Going\n", srb);
/* Append to the list of Going commands */
if (dcb->going_srb)
dcb->going_last->next = srb;
else
dcb->going_srb = srb;
dcb->going_last = srb;
/* No next one in sent list */
srb->next = NULL;
dcb->going_srb_count++;
}
/* Find predecessor SRB */
inline static
struct ScsiReqBlk *find_srb_prev(struct ScsiReqBlk *srb,
struct ScsiReqBlk *start)
void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
{
struct ScsiReqBlk *p = start;
if (!start)
return 0;
do {
if (p->next == srb)
return p;
p = p->next;
} while (p && p != start);
return 0;
dprintkdbg(DBG_0, "srb_going_append: srb %p\n", srb);
list_add_tail(&srb->list, &dcb->srb_going_list);
}
/* Remove SRB from SRB queue */
inline static
struct ScsiReqBlk *remove_srb(struct ScsiReqBlk *srb,
struct ScsiReqBlk *pre)
{
if (pre->next != srb)
pre = find_srb_prev(srb, pre);
if (!pre) {
dprintkl(KERN_ERR, "Internal ERROR: SRB to rmv not found in Q!\n");
return 0;
}
pre->next = srb->next;
/*srb->next = NULL; */
return pre;
}
/* Remove SRB from Going queue */
/*
* srb_going_remove - Remove an srb from the going list stored in the
* dcb.
*/
static
void remove_srb_going(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb,
struct ScsiReqBlk *hint)
void srb_going_remove(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
struct ScsiReqBlk *pre = NULL;
dprintkdbg(DBG_0, "Remove SRB %p from Going\n", srb);
if (!srb)
dprintkl(KERN_ERR, "Going_remove %p!\n", srb);
if (srb == dcb->going_srb)
dcb->going_srb = srb->next;
else if (hint && hint->next == srb)
pre = remove_srb(srb, hint);
else
pre = remove_srb(srb, dcb->going_srb);
if (srb == dcb->going_last)
dcb->going_last = pre;
dcb->going_srb_count--;
struct ScsiReqBlk *i;
struct ScsiReqBlk *tmp;
dprintkdbg(DBG_0, "srb_going_remove: srb %p\n", srb);
list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list)
if (i == srb) {
list_del(&srb->list);
break;
}
}
/* Remove SRB from Waiting queue */
/*
* srb_waiting_remove - Remove an srb from the waiting list stored in the
* dcb.
*/
static
void remove_srb_waiting(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb,
struct ScsiReqBlk *hint)
void srb_waiting_remove(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
struct ScsiReqBlk *pre = NULL;
dprintkdbg(DBG_0, "Remove SRB %p from Waiting\n", srb);
if (!srb)
dprintkl(KERN_ERR, "Waiting_remove %p!\n", srb);
if (srb == dcb->waiting_srb)
dcb->waiting_srb = srb->next;
else if (hint && hint->next == srb)
pre = remove_srb(srb, hint);
else
pre = remove_srb(srb, dcb->waiting_srb);
if (srb == dcb->wait_list)
dcb->wait_list = pre;
dcb->waiting_srb_count--;
struct ScsiReqBlk *i;
struct ScsiReqBlk *tmp;
dprintkdbg(DBG_0, "srb_waiting_remove: srb %p\n", srb);
list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list)
if (i == srb) {
list_del(&srb->list);
break;
}
}
/* Moves SRB from Going list to the top of Waiting list */
/*
* srb_going_to_waiting_move - Remove an srb from the going list in
* the dcb and insert it at the head of the waiting list in the dcb.
*/
static
void move_srb_going_to_waiting(struct DeviceCtlBlk *dcb,
void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
dprintkdbg(DBG_0, "Going_to_Waiting (SRB %p) pid = %li\n", srb, srb->cmd->pid);
/* Remove SRB from Going */
remove_srb_going(dcb, srb, 0);
TRACEPRINTF("GtW *");
/* Insert on top of Waiting */
insert_srb_waiting(dcb, srb);
/* Tag Mask must be freed elsewhere ! (KG, 99/06/18) */
dprintkdbg(DBG_0, "srb_going_waiting_move: srb %p, pid = %li\n", srb, srb->cmd->pid);
list_move(&srb->list, &dcb->srb_waiting_list);
}
/* Moves first SRB from Waiting list to Going list */
static inline
void move_srb_waiting_to_going(struct DeviceCtlBlk *dcb,
/*
* srb_waiting_to_going_move - Remove an srb from the waiting list in
* the dcb and insert it at the head of the going list in the dcb.
*/
static
void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
struct ScsiReqBlk *srb)
{
/* Remove from waiting list */
dprintkdbg(DBG_0, "Remove SRB %p from head of Waiting\n", srb);
remove_srb_waiting(dcb, srb, 0);
dprintkdbg(DBG_0, "srb_waiting_to_going: srb %p\n", srb);
TRACEPRINTF("WtG *");
append_srb_going(dcb, srb);
list_move(&srb->list, &dcb->srb_going_list);
}
......@@ -1070,39 +1069,66 @@ void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to)
static
void waiting_process_next(struct AdapterCtlBlk *acb)
{
struct DeviceCtlBlk *ptr;
struct DeviceCtlBlk *ptr1;
struct DeviceCtlBlk *start = NULL;
struct DeviceCtlBlk *pos;
struct DeviceCtlBlk *dcb;
struct ScsiReqBlk *srb;
struct list_head *dcb_list_head = &acb->dcb_list;
if ((acb->active_dcb)
|| (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV)))
return;
if (timer_pending(&acb->waiting_timer))
del_timer(&acb->waiting_timer);
ptr = acb->dcb_run_robin;
if (!ptr) { /* This can happen! */
ptr = acb->link_dcb;
acb->dcb_run_robin = ptr;
}
ptr1 = ptr;
if (!ptr1)
if (list_empty(dcb_list_head))
return;
/*
* Find the starting dcb. Need to find it again in the list
* since the list may have changed since we set the ptr to it
*/
list_for_each_entry(dcb, dcb_list_head, list)
if (dcb == acb->dcb_run_robin) {
start = dcb;
break;
}
if (!start) {
/* This can happen! */
start = list_entry(dcb_list_head->next, typeof(*start), list);
acb->dcb_run_robin = start;
}
/*
* Loop over the dcb, but we start somewhere (potentially) in
* the middle of the loop so we need to manully do this.
*/
pos = start;
do {
struct list_head *waiting_list_head = &pos->srb_waiting_list;
/* Make sure, the next another device gets scheduled ... */
acb->dcb_run_robin = ptr1->next;
if (!(srb = ptr1->waiting_srb)
|| (ptr1->max_command <= ptr1->going_srb_count))
ptr1 = ptr1->next;
else {
acb->dcb_run_robin = dcb_get_next(dcb_list_head,
acb->dcb_run_robin);
if (list_empty(waiting_list_head) ||
pos->max_command <= list_size(&pos->srb_going_list)) {
/* move to next dcb */
pos = dcb_get_next(dcb_list_head, pos);
} else {
srb = list_entry(waiting_list_head->next,
struct ScsiReqBlk, list);
/* Try to send to the bus */
if (!start_scsi(acb, ptr1, srb))
move_srb_waiting_to_going(ptr1, srb);
if (!start_scsi(acb, pos, srb))
srb_waiting_to_going_move(pos, srb);
else
waiting_set_timer(acb, HZ / 50);
waiting_set_timer(acb, HZ/50);
break;
}
} while (ptr1 != ptr);
return;
} while (pos != start);
}
......@@ -1141,30 +1167,18 @@ void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
struct DeviceCtlBlk *dcb;
dcb = srb->dcb;
if ((dcb->max_command <= dcb->going_srb_count) ||
(acb->active_dcb) ||
if (dcb->max_command <= list_size(&dcb->srb_going_list) ||
acb->active_dcb ||
(acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) {
append_srb_waiting(dcb, srb);
srb_waiting_append(dcb, srb);
waiting_process_next(acb);
return;
}
#if 0
if (dcb->waiting_srb) {
append_srb_waiting(dcb, srb);
/* srb = waiting_srb_get(dcb); *//* non-existent */
srb = dcb->waiting_srb;
/* Remove from waiting list */
dcb->waiting_srb = srb->next;
srb->next = NULL;
if (!dcb->waiting_srb)
dcb->wait_list = NULL;
}
#endif
if (!start_scsi(acb, dcb, srb))
append_srb_going(dcb, srb);
else {
insert_srb_waiting(dcb, srb);
if (!start_scsi(acb, dcb, srb)) {
srb_going_append(dcb, srb);
} else {
srb_waiting_insert(dcb, srb);
waiting_set_timer(acb, HZ / 50);
}
}
......@@ -1391,7 +1405,7 @@ dc395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
cmd->result = 0;
/* get a free SRB */
srb = get_srb_free(acb);
srb = srb_get_free(acb);
if (!srb)
{
/*
......@@ -1405,9 +1419,9 @@ dc395x_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
/* build srb for the command */
build_srb(cmd, dcb, srb);
if (dcb->waiting_srb) {
if (!list_empty(&dcb->srb_waiting_list)) {
/* append to waiting queue */
append_srb_waiting(dcb, srb);
srb_waiting_append(dcb, srb);
waiting_process_next(acb);
} else {
/* process immediately */
......@@ -1609,17 +1623,13 @@ static inline void clear_fifo(struct AdapterCtlBlk *acb, char *txt)
*/
static void reset_dev_param(struct AdapterCtlBlk *acb)
{
struct DeviceCtlBlk *dcb = acb->link_dcb;
struct DeviceCtlBlk *dcb_temp;
struct DeviceCtlBlk *dcb;
struct NvRamType *eeprom = &acb->eeprom;
u8 period_index;
dprintkdbg(DBG_0, "reset_dev_param..............\n");
if (dcb == NULL)
return;
list_for_each_entry(dcb, &acb->dcb_list, list) {
u8 period_index;
dcb_temp = dcb;
do {
dcb->sync_mode &= ~(SYNC_NEGO_DONE + WIDE_NEGO_DONE);
dcb->sync_period = 0;
dcb->sync_offset = 0;
......@@ -1631,10 +1641,7 @@ static void reset_dev_param(struct AdapterCtlBlk *acb)
if (!(dcb->dev_mode & NTC_DO_WIDE_NEGO)
|| !(acb->config & HCC_WIDE_CARD))
dcb->sync_mode &= ~WIDE_NEGO_ENABLE;
dcb = dcb->next;
}
while (dcb_temp != dcb && dcb != NULL);
}
......@@ -1729,18 +1736,18 @@ static int dc395x_eh_abort(Scsi_Cmnd * cmd)
return FAILED;
}
srb = find_cmd(cmd, dcb->waiting_srb);
srb = find_cmd(cmd, &dcb->srb_waiting_list);
if (srb) {
remove_srb_waiting(dcb, srb, 0);
srb_waiting_remove(dcb, srb);
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb);
free_tag(dcb, srb);
insert_srb_free(acb, srb);
srb_free_insert(acb, srb);
dprintkl(KERN_DEBUG, "abort - command found in waiting commands queue");
cmd->result = DID_ABORT << 16;
return SUCCESS;
}
srb = find_cmd(cmd, dcb->going_srb);
srb = find_cmd(cmd, &dcb->srb_going_list);
if (srb) {
dprintkl(KERN_DEBUG, "abort - command currently in progress");
/* XXX: Should abort the command here */
......@@ -3322,23 +3329,27 @@ struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
struct DeviceCtlBlk *dcb,
u8 tag)
{
struct ScsiReqBlk *last_srb = dcb->going_last;
struct ScsiReqBlk *srb = dcb->going_srb;
struct ScsiReqBlk *srb = NULL;
struct ScsiReqBlk *i;
dprintkdbg(DBG_0, "QTag Msg (SRB %p): %i\n", srb, tag);
if (!(dcb->tag_mask & (1 << tag)))
dprintkl(KERN_DEBUG,
"MsgIn_QTag: tag_mask (%08x) does not reserve tag %i!\n",
dcb->tag_mask, tag);
if (!srb)
if (list_empty(&dcb->srb_going_list))
goto mingx0;
while (srb) {
if (srb->tag_number == tag)
list_for_each_entry(i, &dcb->srb_going_list, list) {
if (i->tag_number == tag) {
srb = i;
break;
if (srb == last_srb)
goto mingx0;
srb = srb->next;
}
}
if (!srb)
goto mingx0;
dprintkdbg(DBG_0, "pid %li (%i-%i)\n", srb->cmd->pid,
srb->dcb->target_id, srb->dcb->target_lun);
if (dcb->flag & ABORT_DEV_) {
......@@ -3350,13 +3361,18 @@ struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
goto mingx0;
/* Tag found */
TRACEPRINTF("[%s]*", dcb->active_srb->debugtrace);
TRACEPRINTF("RTag*");
/* Just for debugging ... */
last_srb = srb;
srb = dcb->active_srb;
TRACEPRINTF("Found.*");
srb = last_srb;
{
struct ScsiReqBlk *last_srb;
TRACEPRINTF("[%s]*", dcb->active_srb->debugtrace);
TRACEPRINTF("RTag*");
/* Just for debugging ... */
last_srb = srb;
srb = dcb->active_srb;
TRACEPRINTF("Found.*");
srb = last_srb;
}
memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len);
srb->state |= dcb->active_srb->state;
......@@ -3774,36 +3790,26 @@ void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
static
void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
{
u8 bval;
u16 cnt, i;
struct DeviceCtlBlk *dcb_temp;
struct DeviceCtlBlk *i;
/*
** set all lun device's period , offset
* set all lun device's period , offset
*/
if (!(dcb->identify_msg & 0x07)) {
if (acb->scan_devices)
current_sync_offset = dcb->sync_offset;
else {
dcb_temp = acb->link_dcb;
cnt = acb->dcb_count;
bval = dcb->target_id;
for (i = 0; i < cnt; i++) {
if (dcb_temp->target_id == bval) {
dcb_temp->sync_period =
dcb->sync_period;
dcb_temp->sync_offset =
dcb->sync_offset;
dcb_temp->sync_mode =
dcb->sync_mode;
dcb_temp->min_nego_period =
dcb->min_nego_period;
}
dcb_temp = dcb_temp->next;
}
}
if (dcb->identify_msg & 0x07)
return;
if (acb->scan_devices) {
current_sync_offset = dcb->sync_offset;
return;
}
return;
list_for_each_entry(i, &acb->dcb_list, list)
if (i->target_id == dcb->target_id) {
i->sync_period = dcb->sync_period;
i->sync_offset = dcb->sync_offset;
i->sync_mode = dcb->sync_mode;
i->min_nego_period = dcb->min_nego_period;
}
}
......@@ -3882,7 +3888,7 @@ static void disconnect(struct AdapterCtlBlk *acb)
goto disc1;
}
free_tag(dcb, srb);
move_srb_going_to_waiting(dcb, srb);
srb_going_to_waiting_move(dcb, srb);
dprintkdbg(DBG_KG, "Retry pid %li ...\n",
srb->cmd->pid);
waiting_set_timer(acb, HZ / 20);
......@@ -3964,7 +3970,7 @@ static void reselect(struct AdapterCtlBlk *acb)
srb->state = SRB_READY;
free_tag(dcb, srb);
move_srb_going_to_waiting(dcb, srb);
srb_going_to_waiting_move(dcb, srb);
waiting_set_timer(acb, HZ / 20);
/* return; */
......@@ -4049,43 +4055,32 @@ static void reselect(struct AdapterCtlBlk *acb)
static
void remove_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
{
struct DeviceCtlBlk *pPrevDCB = acb->link_dcb;
struct DeviceCtlBlk *i;
struct DeviceCtlBlk *tmp;
dprintkdbg(DBG_0, "remove_dev\n");
if (dcb->going_srb_count > 1) {
if (list_size(&dcb->srb_going_list) > 1) {
dprintkdbg(DBG_DCB, "Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n",
dcb->target_id, dcb->target_lun, (int) dcb,
dcb->going_srb_count);
list_size(&dcb->srb_going_list));
return;
}
acb->dcb_map[dcb->target_id] &= ~(1 << dcb->target_lun);
acb->children[dcb->target_id][dcb->target_lun] = NULL;
/* The first one */
if (dcb == acb->link_dcb) {
/* The last one */
if (acb->last_dcb == dcb) {
dcb->next = NULL;
acb->last_dcb = NULL;
list_for_each_entry_safe(i, tmp, &acb->dcb_list, list) {
if (dcb == i) {
list_del(&i->list);
break;
}
acb->link_dcb = dcb->next;
} else {
while (pPrevDCB->next != dcb)
pPrevDCB = pPrevDCB->next;
pPrevDCB->next = dcb->next;
if (dcb == acb->last_dcb)
acb->last_dcb = pPrevDCB;
}
}
dprintkdbg(DBG_DCB, "Driver about to free DCB (ID %i, LUN %i): %p\n",
dcb->target_id, dcb->target_lun, dcb);
if (dcb == acb->active_dcb)
acb->active_dcb = NULL;
if (dcb == acb->link_dcb)
acb->link_dcb = dcb->next;
if (dcb == acb->dcb_run_robin)
acb->dcb_run_robin = dcb->next;
acb->dcb_count--;
acb->dcb_run_robin = dcb_get_next(&acb->dcb_list, dcb);
dc395x_kfree(dcb);
}
......@@ -4320,7 +4315,7 @@ void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
request_sense(acb, dcb, srb);
return;
} else if (status_byte(status) == QUEUE_FULL) {
tempcnt = (u8) dcb->going_srb_count;
tempcnt = (u8)list_size(&dcb->srb_going_list);
printk
("\nDC395x: QUEUE_FULL for dev %02i-%i with %i cmnds\n",
dcb->target_id, dcb->target_lun, tempcnt);
......@@ -4328,7 +4323,7 @@ void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
tempcnt--;
dcb->max_command = tempcnt;
free_tag(dcb, srb);
move_srb_going_to_waiting(dcb, srb);
srb_going_to_waiting_move(dcb, srb);
waiting_set_timer(acb, HZ / 20);
srb->adapter_status = 0;
srb->target_status = 0;
......@@ -4409,12 +4404,12 @@ void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
cmd->device->lun, srb->total_xfer_length);
}
remove_srb_going(dcb, srb, 0);
srb_going_remove(dcb, srb);
/* Add to free list */
if (srb == acb->tmp_srb)
dprintkl(KERN_ERR, "ERROR! Completed Cmnd with tmp_srb!\n");
else
insert_srb_free(acb, srb);
srb_free_insert(acb, srb);
dprintkdbg(DBG_0, "SRBdone: done pid %li\n", cmd->pid);
if (debug_enabled(DBG_KG)) {
......@@ -4444,30 +4439,21 @@ void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
Scsi_Cmnd * cmd, u8 force)
{
struct DeviceCtlBlk *dcb;
struct ScsiReqBlk *srb;
struct ScsiReqBlk *srb_temp;
u16 cnt;
Scsi_Cmnd *p;
dcb = acb->link_dcb;
if (!dcb)
return;
dprintkl(KERN_INFO, "doing_srb_done: pids ");
do {
/* As the ML may queue cmnds again, cache old values */
struct ScsiReqBlk *waiting_srb = dcb->waiting_srb;
/*struct ScsiReqBlk* wait_list = dcb->wait_list; */
u16 waiting_srb_count = dcb->waiting_srb_count;
/* Going queue */
cnt = dcb->going_srb_count;
srb = dcb->going_srb;
while (cnt--) {
list_for_each_entry(dcb, &acb->dcb_list, list) {
struct ScsiReqBlk *srb;
struct ScsiReqBlk *tmp;
Scsi_Cmnd *p;
list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) {
int result;
int dir;
srb_temp = srb->next;
p = srb->cmd;
dir = scsi_to_pci_dma_dir(p->sc_data_direction);
result = MK_RES(0, did_flag, 0, 0);
/*result = MK_RES(0,DID_RESET,0,0); */
TRACEPRINTF("Reset(%li):%08x*", jiffies, result);
printk(" (G)");
......@@ -4476,12 +4462,10 @@ void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
p->device->id, p->device->lun);
#endif
TRACEOUT("%s\n", srb->debugtrace);
dcb->going_srb = srb_temp;
dcb->going_srb_count--;
if (!srb_temp)
dcb->going_last = NULL;
srb_going_remove(dcb, srb);
free_tag(dcb, srb);
insert_srb_free(acb, srb);
srb_free_insert(acb, srb);
p->result = result;
pci_unmap_srb_sense(acb, srb);
pci_unmap_srb(acb, srb);
......@@ -4490,9 +4474,8 @@ void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
* as they all complete or all time out */
p->scsi_done(p);
}
srb = srb_temp;
}
if (dcb->going_srb)
if (!list_empty(&dcb->srb_going_list))
dprintkl(KERN_DEBUG,
"How could the ML send cmnds to the Going queue? (%02i-%i)!!\n",
dcb->target_id, dcb->target_lun);
......@@ -4501,16 +4484,12 @@ void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
"tag_mask for %02i-%i should be empty, is %08x!\n",
dcb->target_id, dcb->target_lun,
dcb->tag_mask);
/*dcb->going_srb_count = 0;; */
/*dcb->going_srb = NULL; dcb->going_last = NULL; */
/* Waiting queue */
cnt = waiting_srb_count;
srb = waiting_srb;
while (cnt--) {
list_for_each_entry_safe(srb, tmp, &dcb->srb_waiting_list, list) {
int result;
srb_temp = srb->next;
p = srb->cmd;
result = MK_RES(0, did_flag, 0, 0);
TRACEPRINTF("Reset(%li):%08x*", jiffies, result);
printk(" (W)");
......@@ -4519,11 +4498,8 @@ void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
p->device->lun);
#endif
TRACEOUT("%s\n", srb->debugtrace);
dcb->waiting_srb = srb_temp;
dcb->waiting_srb_count--;
if (!srb_temp)
dcb->wait_list = NULL;
insert_srb_free(acb, srb);
srb_waiting_remove(dcb, srb);
srb_free_insert(acb, srb);
p->result = result;
pci_unmap_srb_sense(acb, srb);
......@@ -4532,21 +4508,16 @@ void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
/* For new EH, we normally don't need to give commands back,
* as they all complete or all time out */
cmd->scsi_done(cmd);
srb = srb_temp;
}
}
if (dcb->waiting_srb_count)
if (!list_empty(&dcb->srb_waiting_list))
printk
("\nDC395x: Debug: ML queued %i cmnds again to %02i-%i\n",
dcb->waiting_srb_count, dcb->target_id,
list_size(&dcb->srb_waiting_list), dcb->target_id,
dcb->target_lun);
/* The ML could have queued the cmnds again! */
/*dcb->waiting_srb_count = 0;; */
/*dcb->waiting_srb = NULL; dcb->wait_list = NULL; */
dcb->flag &= ~ABORT_DEV_;
dcb = dcb->next;
}
while (dcb != acb->link_dcb && dcb);
printk("\n");
}
......@@ -4703,7 +4674,7 @@ void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
"Request Sense failed for pid %li (%02i-%i)!\n",
srb->cmd->pid, dcb->target_id, dcb->target_lun);
TRACEPRINTF("?*");
move_srb_going_to_waiting(dcb, srb);
srb_going_to_waiting_move(dcb, srb);
waiting_set_timer(acb, HZ / 100);
}
TRACEPRINTF(".*");
......@@ -4736,26 +4707,17 @@ void init_dcb(struct AdapterCtlBlk *acb, struct DeviceCtlBlk **pdcb,
if (!dcb)
return;
if (acb->dcb_count == 0) {
acb->link_dcb = dcb;
INIT_LIST_HEAD(&dcb->srb_waiting_list);
INIT_LIST_HEAD(&dcb->srb_going_list);
if (list_empty(&acb->dcb_list))
acb->dcb_run_robin = dcb;
} else {
acb->last_dcb->next = dcb;
}
acb->dcb_count++;
dcb->next = acb->link_dcb;
acb->last_dcb = dcb;
list_add_tail(&dcb->list, &acb->dcb_list);
/* $$$$$$$ */
dcb->acb = acb;
dcb->target_id = target;
dcb->target_lun = lun;
/* $$$$$$$ */
dcb->waiting_srb = NULL;
dcb->going_srb = NULL;
dcb->going_srb_count = 0;
dcb->waiting_srb_count = 0;
dcb->active_srb = NULL;
/* $$$$$$$ */
dcb->tag_mask = 0;
......@@ -4792,9 +4754,10 @@ void init_dcb(struct AdapterCtlBlk *acb, struct DeviceCtlBlk **pdcb,
/* $$$$$$$ */
if (dcb->target_lun != 0) {
/* Copy settings */
struct DeviceCtlBlk *prevDCB = acb->link_dcb;
while (prevDCB->target_id != dcb->target_id)
prevDCB = prevDCB->next;
struct DeviceCtlBlk *prevDCB;
list_for_each_entry(prevDCB, &acb->dcb_list, list)
if (prevDCB->target_id == dcb->target_id)
break;
dprintkdbg(DBG_KG,
"Copy settings from %02i-%02i to %02i-%02i\n",
prevDCB->target_id, prevDCB->target_lun,
......@@ -4924,9 +4887,7 @@ static void __init link_srb(struct AdapterCtlBlk *acb)
int i;
for (i = 0; i < acb->srb_count - 1; i++)
acb->srb_array[i].next = &acb->srb_array[i + 1];
acb->srb_array[i].next = NULL;
/*DC395x_Free_integrity (acb); */
srb_free_insert(acb, &acb->srb_array[i]);
}
......@@ -4974,14 +4935,12 @@ int __init init_acb(struct Scsi_Host *host, u32 io_port, u8 irq)
*/
acb->scsi_host = host;
acb->IOPortBase = (u16) io_port;
acb->link_dcb = NULL;
acb->dcb_run_robin = NULL;
acb->active_dcb = NULL;
acb->srb_count = DC395x_MAX_SRB_CNT;
acb->scsi_host->this_id = eeprom->scsi_id;
acb->hostid_bit = (1 << acb->scsi_host->this_id);
/*acb->scsi_host->this_lun = 0; */
acb->dcb_count = 0;
acb->irq_level = irq;
acb->tag_max_num = 1 << eeprom->max_tag;
if (acb->tag_max_num > 30)
......@@ -5006,14 +4965,14 @@ int __init init_acb(struct Scsi_Host *host, u32 io_port, u8 irq)
return 1;
}
#endif
INIT_LIST_HEAD(&acb->dcb_list);
INIT_LIST_HEAD(&acb->srb_free_list);
link_srb(acb);
acb->free_srb = acb->srb_array;
/*
* temp SRB for Q tag used or abort command used
*/
acb->tmp_srb = &acb->srb;
acb->srb.dcb = NULL;
acb->srb.next = NULL;
init_timer(&acb->waiting_timer);
for (i = 0; i < DC395x_MAX_SCSI_ID; i++)
......@@ -5550,10 +5509,11 @@ int dc395x_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t o
int inout)
{
struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
int dev, spd, spd1;
int spd, spd1;
char *pos = buffer;
struct DeviceCtlBlk *dcb;
unsigned long flags;
int dev;
if (inout) /* Has data been written to the file ? */
return -EPERM;
......@@ -5580,7 +5540,7 @@ int dc395x_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t o
SPRINTF(", DelayReset %is\n", acb->eeprom.delay_time);
/*SPRINTF("\n"); */
SPRINTF("Nr of DCBs: %i\n", acb->dcb_count);
SPRINTF("Nr of DCBs: %i\n", list_size(&acb->dcb_list));
SPRINTF
("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n",
acb->dcb_map[0], acb->dcb_map[1], acb->dcb_map[2],
......@@ -5595,8 +5555,8 @@ int dc395x_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t o
SPRINTF
("Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n");
dcb = acb->link_dcb;
for (dev = 0; dev < acb->dcb_count; dev++) {
dev = 0;
list_for_each_entry(dcb, &acb->dcb_list, list) {
int nego_period;
SPRINTF("%02i %02i %02i ", dev, dcb->target_id,
dcb->target_lun);
......@@ -5606,8 +5566,7 @@ int dc395x_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t o
YESNO(dcb->dev_mode & NTC_DO_DISCONNECT);
YESNO(dcb->dev_mode & NTC_DO_SEND_START);
YESNO(dcb->sync_mode & EN_TAG_QUEUEING);
nego_period =
clock_period[dcb->sync_period & 0x07] << 2;
nego_period = clock_period[dcb->sync_period & 0x07] << 2;
if (dcb->sync_offset)
SPRINTF(" %03i ns ", nego_period);
else
......@@ -5624,45 +5583,42 @@ int dc395x_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t o
/* Add more info ... */
SPRINTF(" %02i\n", dcb->max_command);
dcb = dcb->next;
dev++;
}
if (timer_pending(&acb->waiting_timer))
SPRINTF("Waiting queue timer running\n");
else
SPRINTF("\n");
dcb = acb->link_dcb;
for (dev = 0; dev < acb->dcb_count; dev++) {
list_for_each_entry(dcb, &acb->dcb_list, list) {
struct ScsiReqBlk *srb;
if (dcb->waiting_srb_count)
if (!list_empty(&dcb->srb_waiting_list))
SPRINTF("DCB (%02i-%i): Waiting: %i:",
dcb->target_id, dcb->target_lun,
dcb->waiting_srb_count);
for (srb = dcb->waiting_srb; srb; srb = srb->next)
list_size(&dcb->srb_waiting_list));
list_for_each_entry(srb, &dcb->srb_waiting_list, list)
SPRINTF(" %li", srb->cmd->pid);
if (dcb->going_srb_count)
if (!list_empty(&dcb->srb_going_list))
SPRINTF("\nDCB (%02i-%i): Going : %i:",
dcb->target_id, dcb->target_lun,
dcb->going_srb_count);
for (srb = dcb->going_srb; srb; srb = srb->next)
list_size(&dcb->srb_going_list));
list_for_each_entry(srb, &dcb->srb_going_list, list)
#if debug_enabled(DBG_TRACE|DBG_TRACEALL)
SPRINTF("\n %s", srb->debugtrace);
#else
SPRINTF(" %li", srb->cmd->pid);
#endif
if (dcb->waiting_srb_count || dcb->going_srb_count)
if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
SPRINTF("\n");
dcb = dcb->next;
}
if (debug_enabled(DBG_DCB)) {
SPRINTF("DCB list for ACB %p:\n", acb);
dcb = acb->link_dcb;
SPRINTF("%p", dcb);
for (dev = 0; dev < acb->dcb_count; dev++, dcb = dcb->next)
SPRINTF("->%p", dcb->next);
SPRINTF("\n");
list_for_each_entry(dcb, &acb->dcb_list, list) {
SPRINTF("%p -> ", dcb);
}
SPRINTF("END\n");
}
*start = buffer + offset;
......@@ -5721,19 +5677,13 @@ static
void free_dcbs(struct AdapterCtlBlk* acb)
{
struct DeviceCtlBlk *dcb;
struct DeviceCtlBlk *dcb_next;
struct DeviceCtlBlk *tmp;
dprintkdbg(DBG_DCB, "Free %i DCBs\n", acb->dcb_count);
dprintkdbg(DBG_DCB, "Free %i DCBs\n", list_size(&acb->dcb_list));
for (dcb = acb->link_dcb; dcb != NULL; dcb = dcb_next)
{
dcb_next = dcb->next;
list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list) {
dprintkdbg(DBG_DCB, "Free DCB (ID %i, LUN %i): %p\n",
dcb->target_id, dcb->target_lun, dcb);
/*
* Free the DCB. This removes the entry from the
* link_dcb list and decrements the count in dcb_count
*/
remove_dev(acb, dcb);
}
}
......@@ -5862,14 +5812,7 @@ static void __devexit dc395x_remove_one(struct pci_dev *dev)
struct Scsi_Host *host = pci_get_drvdata(dev);
dprintkdbg(DBG_0, "Removing instance\n");
if (!host) {
dprintkl(KERN_ERR, "no host allocated\n");
return;
}
if (scsi_remove_host(host)) {
dprintkl(KERN_ERR, "scsi_remove_host failed\n");
return;
}
scsi_remove_host(host);
host_release(host);
scsi_host_put(host);
pci_set_drvdata(dev, NULL);
......
......@@ -40,6 +40,16 @@
static int scsi_host_next_hn; /* host_no for next new host */
static void scsi_host_cls_release(struct class_device *class_dev)
{
put_device(&class_to_shost(class_dev)->shost_gendev);
}
static struct class shost_class = {
.name = "scsi_host",
.release = scsi_host_cls_release,
};
/**
* scsi_host_cancel - cancel outstanding IO to this host
* @shost: pointer to struct Scsi_Host
......@@ -64,10 +74,18 @@ void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
**/
void scsi_remove_host(struct Scsi_Host *shost)
{
unsigned long flags;
scsi_host_cancel(shost, 0);
scsi_proc_host_rm(shost);
scsi_forget_host(shost);
scsi_sysfs_remove_host(shost);
spin_lock_irqsave(shost->host_lock, flags);
set_bit(SHOST_DEL, &shost->shost_state);
spin_unlock_irqrestore(shost->host_lock, flags);
class_device_unregister(&shost->shost_classdev);
device_del(&shost->shost_gendev);
}
/**
......@@ -89,21 +107,45 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
if (!shost->can_queue) {
printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
sht->name);
error = -EINVAL;
return -EINVAL;
}
error = scsi_sysfs_add_host(shost, dev);
if (!error)
scsi_proc_host_add(shost);
if (!shost->shost_gendev.parent)
shost->shost_gendev.parent = dev ? dev : &legacy_bus;
error = device_add(&shost->shost_gendev);
if (error)
goto out;
set_bit(SHOST_ADD, &shost->shost_state);
get_device(shost->shost_gendev.parent);
error = class_device_add(&shost->shost_classdev);
if (error)
goto out_del_gendev;
get_device(&shost->shost_gendev);
error = scsi_sysfs_add_host(shost);
if (error)
goto out_del_classdev;
scsi_proc_host_add(shost);
return error;
out_del_classdev:
class_device_del(&shost->shost_classdev);
out_del_gendev:
device_del(&shost->shost_gendev);
out:
return error;
}
/**
* scsi_free_sdev - free a scsi hosts resources
* @shost: scsi host to free
**/
void scsi_free_shost(struct Scsi_Host *shost)
static void scsi_host_dev_release(struct device *dev)
{
struct Scsi_Host *shost = dev_to_shost(dev);
struct device *parent = dev->parent;
if (shost->ehandler) {
DECLARE_COMPLETION(sem);
shost->eh_notify = &sem;
......@@ -115,6 +157,8 @@ void scsi_free_shost(struct Scsi_Host *shost)
scsi_proc_hostdir_rm(shost->hostt);
scsi_destroy_command_freelist(shost);
put_device(parent);
kfree(shost);
}
......@@ -214,7 +258,16 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
if (rval)
goto fail;
scsi_sysfs_init_host(shost);
device_initialize(&shost->shost_gendev);
snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
shost->host_no);
shost->shost_gendev.release = scsi_host_dev_release;
class_device_initialize(&shost->shost_classdev);
shost->shost_classdev.dev = &shost->shost_gendev;
shost->shost_classdev.class = &shost_class;
snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
shost->eh_notify = &complete;
/* XXX(hch): handle error return */
......@@ -299,3 +352,13 @@ void scsi_host_put(struct Scsi_Host *shost)
{
put_device(&shost->shost_gendev);
}
int scsi_init_hosts(void)
{
return class_register(&shost_class);
}
void scsi_exit_hosts(void)
{
class_unregister(&shost_class);
}
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -106,8 +106,10 @@
#define IPS_REMOVE_HOST(shost)
#define IPS_SCSI_SET_DEVICE(sh,ha) scsi_set_pci_device(sh, (ha)->pcidev)
#define IPS_PRINTK(level, pcidev, format, arg...) \
printk(level "%s %s:" format , (pcidev)->driver->name , \
pci_name(pcidev) , ## arg)
printk(level "%s %s:" format , "ips" , \
(pcidev)->slot_name , ## arg)
#define scsi_host_alloc(sh,size) scsi_register(sh,size)
#define scsi_host_put(sh) scsi_unregister(sh)
#else
#define IPS_REGISTER_HOSTS(SHT) (!ips_detect(SHT))
#define IPS_UNREGISTER_HOSTS(SHT)
......@@ -126,22 +128,13 @@
#define min(x,y) ((x) < (y) ? x : y)
#endif
#define pci_dma_hi32(a) ((a >> 16) >> 16)
#define pci_dma_lo32(a) (a & 0xffffffff)
#if (BITS_PER_LONG > 32) || (defined CONFIG_HIGHMEM64G && defined IPS_HIGHIO)
#define IPS_ENABLE_DMA64 (1)
#define pci_dma_hi32(a) (a >> 32)
#else
#define IPS_ENABLE_DMA64 (0)
#define pci_dma_hi32(a) (0)
#endif
#if defined(__ia64__)
#define IPS_ATOMIC_GFP (GFP_DMA | GFP_ATOMIC)
#define IPS_INIT_GFP GFP_DMA
#else
#define IPS_ATOMIC_GFP GFP_ATOMIC
#define IPS_INIT_GFP GFP_KERNEL
#endif
/*
......@@ -451,9 +444,11 @@
* Scsi_Host Template
*/
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
static int ips_proc24_info(char *, char **, off_t, int, int, int);
static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
#else
int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
sector_t capacity, int geom[]);
int ips_slave_configure(Scsi_Device *SDptr);
......@@ -1106,7 +1101,8 @@ typedef struct ips_ha {
uint16_t device_id; /* PCI device ID */
uint8_t slot_num; /* PCI Slot Number */
uint16_t subdevice_id; /* Subsystem device ID */
uint8_t ioctl_order; /* Number of pages in ioctl */
int ioctl_len; /* size of ioctl buffer */
dma_addr_t ioctl_busaddr; /* dma address of ioctl buffer*/
uint8_t bios_version[8]; /* BIOS Revision */
uint32_t mem_addr; /* Memory mapped address */
uint32_t io_len; /* Size of IO Address */
......@@ -1116,8 +1112,10 @@ typedef struct ips_ha {
ips_hw_func_t func; /* hw function pointers */
struct pci_dev *pcidev; /* PCI device handle */
char *flash_data; /* Save Area for flash data */
u8 flash_order; /* Save Area for flash size order */
int flash_len; /* length of flash buffer */
u32 flash_datasize; /* Save Area for flash data size */
dma_addr_t flash_busaddr; /* dma address of flash buffer*/
dma_addr_t enq_busaddr; /* dma address of enq struct */
uint8_t requires_esl; /* Requires an EraseStripeLock */
} ips_ha_t;
......@@ -1203,25 +1201,29 @@ typedef struct {
*
*************************************************************************/
#define IPS_VER_MAJOR 5
#define IPS_VER_MAJOR_STRING "5"
#define IPS_VER_MINOR 99
#define IPS_VER_MINOR_STRING "99"
#define IPS_VER_BUILD 00
#define IPS_VER_BUILD_STRING "00"
#define IPS_VER_STRING "5.99.00"
#define IPS_BUILD_IDENT 1132
#define IPS_VER_MAJOR 6
#define IPS_VER_MAJOR_STRING "6"
#define IPS_VER_MINOR 10
#define IPS_VER_MINOR_STRING "10"
#define IPS_VER_BUILD 90
#define IPS_VER_BUILD_STRING "90"
#define IPS_VER_STRING "6.10.90"
#define IPS_RELEASE_ID 0x00010000
#define IPS_BUILD_IDENT 364
#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2003. All Rights Reserved."
#define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to present. All Rights Reserved."
#define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2003."
/* Version numbers for various adapters */
#define IPS_VER_SERVERAID1 "2.25.01"
#define IPS_VER_SERVERAID2 "2.88.13"
#define IPS_VER_NAVAJO "2.88.13"
#define IPS_VER_SERVERAID3 "5.11.05"
#define IPS_VER_SERVERAID4H "5.11.05"
#define IPS_VER_SERVERAID4MLx "5.11.05"
#define IPS_VER_SARASOTA "5.11.05"
#define IPS_VER_MARCO "0.00.00"
#define IPS_VER_SEBRING "0.00.00"
#define IPS_VER_SERVERAID3 "6.10.24"
#define IPS_VER_SERVERAID4H "6.10.24"
#define IPS_VER_SERVERAID4MLx "6.10.24"
#define IPS_VER_SARASOTA "6.10.24"
#define IPS_VER_MARCO "6.10.24"
#define IPS_VER_SEBRING "6.10.24"
/* Compatability IDs for various adapters */
#define IPS_COMPAT_UNKNOWN ""
......@@ -1230,17 +1232,17 @@ typedef struct {
#define IPS_COMPAT_SERVERAID2 "2.88.13"
#define IPS_COMPAT_NAVAJO "2.88.13"
#define IPS_COMPAT_KIOWA "2.88.13"
#define IPS_COMPAT_SERVERAID3H "SA510"
#define IPS_COMPAT_SERVERAID3L "SA510"
#define IPS_COMPAT_SERVERAID4H "SA510"
#define IPS_COMPAT_SERVERAID4M "SA510"
#define IPS_COMPAT_SERVERAID4L "SA510"
#define IPS_COMPAT_SERVERAID4Mx "SA510"
#define IPS_COMPAT_SERVERAID4Lx "SA510"
#define IPS_COMPAT_SARASOTA "SA510"
#define IPS_COMPAT_MARCO "SA000"
#define IPS_COMPAT_SEBRING "SA000"
#define IPS_COMPAT_BIOS "SA510"
#define IPS_COMPAT_SERVERAID3H "SB610"
#define IPS_COMPAT_SERVERAID3L "SB610"
#define IPS_COMPAT_SERVERAID4H "SB610"
#define IPS_COMPAT_SERVERAID4M "SB610"
#define IPS_COMPAT_SERVERAID4L "SB610"
#define IPS_COMPAT_SERVERAID4Mx "SB610"
#define IPS_COMPAT_SERVERAID4Lx "SB610"
#define IPS_COMPAT_SARASOTA "SB610"
#define IPS_COMPAT_MARCO "SB610"
#define IPS_COMPAT_SEBRING "SB610"
#define IPS_COMPAT_BIOS "SB610"
#define IPS_COMPAT_MAX_ADAPTER_TYPE 16
#define IPS_COMPAT_ID_LENGTH 8
......
......@@ -86,14 +86,10 @@ lasi700_driver_callback(struct parisc_device *dev)
struct NCR_700_Host_Parameters *hostdata;
struct Scsi_Host *host;
snprintf(dev->dev.name, sizeof(dev->dev.name), "%s",
(dev->id.sversion == LASI_700_SVERSION) ?
"lasi700" : "lasi710");
hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
if (!hostdata) {
printk(KERN_ERR "%s: Failed to allocate host data\n",
dev->dev.name);
dev->dev.bus_id);
return 1;
}
memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
......@@ -121,9 +117,9 @@ lasi700_driver_callback(struct parisc_device *dev)
host->irq = dev->irq;
if (request_irq(dev->irq, NCR_700_intr, SA_SHIRQ,
dev->dev.name, host)) {
dev->dev.bus_id, host)) {
printk(KERN_ERR "%s: irq problem, detaching\n",
dev->dev.name);
dev->dev.bus_id);
goto out_put_host;
}
......
......@@ -177,13 +177,8 @@ static void aha152x_detach(dev_link_t *link)
if (*linkp == NULL)
return;
if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG)
aha152x_release_cs(link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
if (link->handle)
CardServices(DeregisterClient, link->handle);
......@@ -302,9 +297,6 @@ static void aha152x_release_cs(dev_link_t *link)
link->state &= ~DEV_CONFIG;
scsi_unregister(info->host);
if (link->state & DEV_STALE_LINK)
aha152x_detach(link);
}
static int aha152x_event(event_t event, int priority,
......
......@@ -166,13 +166,8 @@ static void fdomain_detach(dev_link_t *link)
if (*linkp == NULL)
return;
if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG)
fdomain_release(link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
if (link->handle)
CardServices(DeregisterClient, link->handle);
......@@ -283,9 +278,7 @@ static void fdomain_release(dev_link_t *link)
scsi_unregister(info->host);
link->state &= ~DEV_CONFIG;
if (link->state & DEV_STALE_LINK)
fdomain_detach(link);
} /* fdomain_release */
}
/*====================================================================*/
......
......@@ -1553,18 +1553,12 @@ static void nsp_cs_detach(dev_link_t *link)
return;
}
if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG)
nsp_cs_release(link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
/* Break the link with Card Services */
if (link->handle) {
if (link->handle)
CardServices(DeregisterClient, link->handle);
}
/* Unlink device structure, free bits */
*linkp = link->next;
......@@ -1792,17 +1786,6 @@ static void nsp_cs_release(dev_link_t *link)
DEBUG(0, "%s(0x%p)\n", __FUNCTION__, link);
/*
* If the device is currently in use, we won't release until it
* is actually closed.
*/
if (link->open) {
DEBUG(1, "nsp_cs: release postponed, '%s' still open\n",
link->dev->dev_name);
link->state |= DEV_STALE_CONFIG;
return;
}
/* Unlink the device chain */
#if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,2))
scsi_unregister_module(MODULE_SCSI_HA, &nsp_driver_template);
......@@ -1824,11 +1807,7 @@ static void nsp_cs_release(dev_link_t *link)
CardServices(ReleaseIRQ, link->handle, &link->irq);
}
link->state &= ~DEV_CONFIG;
if (link->state & DEV_STALE_LINK) {
nsp_cs_detach(link);
}
} /* nsp_cs_release */
}
/*======================================================================
......
......@@ -165,13 +165,8 @@ static void qlogic_detach(dev_link_t * link)
if (*linkp == NULL)
return;
if (link->state & DEV_CONFIG) {
if (link->state & DEV_CONFIG)
qlogic_release(link);
if (link->state & DEV_STALE_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
if (link->handle)
CardServices(DeregisterClient, link->handle);
......@@ -296,9 +291,7 @@ static void qlogic_release(dev_link_t *link)
scsi_unregister(info->host);
link->state &= ~DEV_CONFIG;
if (link->state & DEV_STALE_LINK)
qlogic_detach(link);
} /* qlogic_release */
}
/*====================================================================*/
......
......@@ -76,6 +76,7 @@ int ppa_release(struct Scsi_Host *host)
int host_no = host->unique_id;
printk("Releasing ppa%i\n", host_no);
scsi_unregister(host);
parport_unregister_device(ppa_hosts[host_no].dev);
return 0;
}
......
......@@ -16,9 +16,11 @@
* General Public License for more details.
*
******************************************************************************/
#define QLA1280_VERSION "3.23.34"
#define QLA1280_VERSION "3.23.35"
/*****************************************************************************
Revision History:
Rev 3.23.35 August 14, 2003, Jes Sorensen
- Build against 2.6
Rev 3.23.34 July 23, 2003, Jes Sorensen
- Remove pointless TRUE/FALSE macros
- Clean up vchan handling
......@@ -296,14 +298,12 @@
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/pci_ids.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
......@@ -312,7 +312,10 @@
#include <asm/system.h>
#if LINUX_VERSION_CODE < 0x020545
#include <linux/blk.h>
#include "sd.h"
#else
#include <scsi/scsi_host.h>
#endif
#include "scsi.h"
#include "hosts.h"
......@@ -634,11 +637,14 @@ static int ql_debug_level = 1;
*************************************************************************/
#define PROC_BUF &qla1280_buffer[len]
int
qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout)
#if LINUX_VERSION_CODE < 0x020600
int qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout)
#else
int qla1280_proc_info(struct Scsi_Host *host, char *buffer, char **start,
off_t offset, int length, int inout)
#endif
{
struct Scsi_Host *host;
struct scsi_qla_host *ha;
int size = 0;
int len = 0;
......@@ -647,7 +653,10 @@ qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
struct scsi_lu *up;
uint32_t b, t, l;
#endif
#if LINUX_VERSION_CODE >= 0x020600
ha = (struct scsi_qla_host *)host->hostdata;
#else
struct Scsi_Host *host;
/* Find the host that was specified */
for (ha = qla1280_hostlist; (ha != NULL)
&& ha->host->host_no != hostno; ha = ha->next) ;
......@@ -664,6 +673,7 @@ qla1280_proc_info(char *buffer, char **start, off_t offset, int length,
}
host = ha->host;
#endif
if (inout)
return -ENOSYS;
......@@ -1828,7 +1838,7 @@ qla1280_done(struct scsi_qla_host *ha, struct srb ** done_q_first,
CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE;
ha->actthreads--;
#if LINUX_KERNEL_VERSION < 0x020500
#if LINUX_VERSION_CODE < 0x020500
if (cmd->cmnd[0] == INQUIRY)
qla1280_get_target_options(cmd, ha);
#endif
......@@ -4497,7 +4507,7 @@ qla1280_rst_aen(struct scsi_qla_host *ha)
}
#if LINUX_KERNEL_VERSION < 0x020500
#if LINUX_VERSION_CODE < 0x020500
/*
*
*/
......
......@@ -1111,7 +1111,11 @@ struct scsi_qla_host {
/*
* Linux - SCSI Driver Interface Function Prototypes.
*/
#if LINUX_VERSION_CODE < 0x020600
int qla1280_proc_info(char *, char **, off_t, int, int, int);
#else
int qla1280_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
#endif
const char *qla1280_info(struct Scsi_Host *host);
int qla1280_detect(Scsi_Host_Template *);
int qla1280_release(struct Scsi_Host *);
......@@ -1147,8 +1151,6 @@ int qla1280_eh_adapter_reset(struct scsi_cmnd *cmd);
.detect = qla1280_detect, \
.release = qla1280_release, \
.info = qla1280_info, \
.ioctl = NULL, \
.command = NULL, \
.queuecommand = qla1280_queuecommand, \
.eh_strategy_handler = NULL, \
.eh_abort_handler = qla1280_eh_abort, \
......
......@@ -1003,9 +1003,12 @@ static int __init init_scsi(void)
error = scsi_init_devinfo();
if (error)
goto cleanup_procfs;
error = scsi_sysfs_register();
error = scsi_init_hosts();
if (error)
goto cleanup_devlist;
error = scsi_sysfs_register();
if (error)
goto cleanup_hosts;
for (i = 0; i < NR_CPUS; i++)
INIT_LIST_HEAD(&done_q[i]);
......@@ -1015,6 +1018,8 @@ static int __init init_scsi(void)
printk(KERN_NOTICE "SCSI subsystem initialized\n");
return 0;
cleanup_hosts:
scsi_exit_hosts();
cleanup_devlist:
scsi_exit_devinfo();
cleanup_procfs:
......@@ -1029,6 +1034,7 @@ static int __init init_scsi(void)
static void __exit exit_scsi(void)
{
scsi_sysfs_unregister();
scsi_exit_hosts();
scsi_exit_devinfo();
devfs_remove("scsi");
scsi_exit_procfs();
......
......@@ -1285,7 +1285,12 @@ int scsi_decide_disposition(struct scsi_cmnd *scmd)
maybe_retry:
if ((++scmd->retries) < scmd->allowed) {
/* we requeue for retry because the error was retryable, and
* the request was not marked fast fail. Note that above,
* even if the request is marked fast fail, we still requeue
* for queue congestion conditions (QUEUE_FULL or BUSY) */
if ((++scmd->retries) < scmd->allowed
&& !blk_noretry_request(scmd->request)) {
return NEEDS_RETRY;
} else {
/*
......
......@@ -502,14 +502,22 @@ static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
* to queue the remainder of them.
*/
if (end_that_request_first(req, uptodate, sectors)) {
if (requeue) {
/*
* Bleah. Leftovers again. Stick the leftovers in
* the front of the queue, and goose the queue again.
*/
scsi_requeue_command(q, cmd);
int leftover = req->hard_nr_sectors - sectors;
/* kill remainder if no retrys */
if (!uptodate && blk_noretry_request(req))
end_that_request_first(req, 0, leftover);
else {
if (requeue)
/*
* Bleah. Leftovers again. Stick the
* leftovers in the front of the
* queue, and goose the queue again.
*/
scsi_requeue_command(q, cmd);
return cmd;
}
return cmd;
}
add_disk_randomness(req->rq_disk);
......
......@@ -41,6 +41,12 @@
#define SCSI_SENSE_VALID(scmd) \
(((scmd)->sense_buffer[0] & 0x70) == 0x70)
/*
* Special value for scanning to specify scanning or rescanning of all
* possible channels, (target) ids, or luns on a given shost.
*/
#define SCAN_WILD_CARD ~0
/*
* scsi_target: representation of a scsi target, for now, this is only
* used for single_lun devices. If no one has active IO to the target,
......@@ -51,6 +57,9 @@ struct scsi_target {
unsigned int starget_refcnt;
};
/* hosts.c */
extern int scsi_init_hosts(void);
extern void scsi_exit_hosts(void);
/* scsi.c */
extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
......@@ -106,20 +115,18 @@ extern void scsi_exit_procfs(void);
#endif /* CONFIG_PROC_FS */
/* scsi_scan.c */
int scsi_scan_host_selected(struct Scsi_Host *, unsigned int, unsigned int,
unsigned int, int);
extern void scsi_forget_host(struct Scsi_Host *);
extern void scsi_free_sdev(struct scsi_device *);
extern void scsi_free_shost(struct Scsi_Host *);
extern void scsi_rescan_device(struct device *);
/* scsi_sysfs.c */
extern int scsi_device_register(struct scsi_device *);
extern void scsi_sysfs_init_host(struct Scsi_Host *);
extern int scsi_sysfs_add_host(struct Scsi_Host *, struct device *);
extern void scsi_sysfs_remove_host(struct Scsi_Host *);
extern int scsi_sysfs_add_host(struct Scsi_Host *);
extern int scsi_sysfs_register(void);
extern void scsi_sysfs_unregister(void);
extern struct class shost_class;
extern struct class sdev_class;
extern struct bus_type scsi_bus_type;
......
......@@ -81,6 +81,9 @@ static int proc_scsi_write_proc(struct file *file, const char *buf,
void scsi_proc_hostdir_add(struct scsi_host_template *sht)
{
if (!sht->proc_info)
return;
down(&global_host_template_sem);
if (!sht->present++) {
sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
......@@ -96,6 +99,9 @@ void scsi_proc_hostdir_add(struct scsi_host_template *sht)
void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
{
if (!sht->proc_info)
return;
down(&global_host_template_sem);
if (!--sht->present && sht->proc_dir) {
remove_proc_entry(sht->proc_name, proc_scsi);
......@@ -189,21 +195,13 @@ static int proc_print_scsidevice(struct device *dev, void *data)
static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
{
struct Scsi_Host *shost;
struct scsi_device *sdev;
int error = -ENXIO;
shost = scsi_host_lookup(host);
if (IS_ERR(shost))
return PTR_ERR(shost);
if (!scsi_find_device(shost, channel, id, lun)) {
sdev = scsi_add_device(shost, channel, id, lun);
if (IS_ERR(sdev))
error = PTR_ERR(sdev);
else
error = 0;
}
error = scsi_scan_host_selected(shost, channel, id, lun, 1);
scsi_host_put(shost);
return error;
}
......
......@@ -656,13 +656,32 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
**/
static int scsi_probe_and_add_lun(struct Scsi_Host *host,
uint channel, uint id, uint lun, int *bflagsp,
struct scsi_device **sdevp)
struct scsi_device **sdevp, int rescan)
{
struct scsi_device *sdev;
struct scsi_request *sreq;
unsigned char *result;
int bflags, res = SCSI_SCAN_NO_RESPONSE;
/*
* The rescan flag is used as an optimization, the first scan of a
* host adapter calls into here with rescan == 0.
*/
if (rescan) {
sdev = scsi_find_device(host, channel, id, lun);
if (sdev) {
SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
"scsi scan: device exists on <%d:%d:%d:%d>\n",
host->host_no, channel, id, lun));
if (sdevp)
*sdevp = sdev;
if (bflagsp)
*bflagsp = scsi_get_device_flags(sdev->vendor,
sdev->model);
return SCSI_SCAN_LUN_PRESENT;
}
}
sdev = scsi_alloc_sdev(host, channel, id, lun);
if (!sdev)
goto out;
......@@ -737,7 +756,7 @@ static int scsi_probe_and_add_lun(struct Scsi_Host *host,
* Modifies sdevscan->lun.
**/
static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel,
uint id, int bflags, int lun0_res, int scsi_level)
uint id, int bflags, int lun0_res, int scsi_level, int rescan)
{
unsigned int sparse_lun, lun, max_dev_lun;
......@@ -806,7 +825,8 @@ static void scsi_sequential_lun_scan(struct Scsi_Host *shost, uint channel,
*/
for (lun = 1; lun < max_dev_lun; ++lun)
if ((scsi_probe_and_add_lun(shost, channel, id, lun,
NULL, NULL) != SCSI_SCAN_LUN_PRESENT) && !sparse_lun)
NULL, NULL, rescan) != SCSI_SCAN_LUN_PRESENT) &&
!sparse_lun)
return;
}
......@@ -857,7 +877,8 @@ static int scsilun_to_int(struct scsi_lun *scsilun)
* 0: scan completed (or no memory, so further scanning is futile)
* 1: no report lun scan, or not configured
**/
static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
int rescan)
{
char devname[64];
unsigned char scsi_cmd[MAX_COMMAND_SIZE];
......@@ -1011,7 +1032,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
int res;
res = scsi_probe_and_add_lun(sdev->host, sdev->channel,
sdev->id, lun, NULL, NULL);
sdev->id, lun, NULL, NULL, rescan);
if (res == SCSI_SCAN_NO_RESPONSE) {
/*
* Got some results, but now none, abort.
......@@ -1037,7 +1058,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags)
return 0;
}
#else
# define scsi_report_lun_scan(sdev, blags) (1)
# define scsi_report_lun_scan(sdev, blags, rescan) (1)
#endif /* CONFIG_SCSI_REPORT_LUNS */
struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
......@@ -1046,7 +1067,7 @@ struct scsi_device *scsi_add_device(struct Scsi_Host *shost,
struct scsi_device *sdev;
int res;
res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev);
res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev, 1);
if (res != SCSI_SCAN_LUN_PRESENT)
sdev = ERR_PTR(-ENODEV);
return sdev;
......@@ -1083,7 +1104,7 @@ void scsi_rescan_device(struct device *dev)
* sequential scan of LUNs on the target id.
**/
static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
unsigned int id)
unsigned int id, unsigned int lun, int rescan)
{
int bflags = 0;
int res;
......@@ -1095,19 +1116,29 @@ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
*/
return;
if (lun != SCAN_WILD_CARD) {
/*
* Scan for a specific host/chan/id/lun.
*/
scsi_probe_and_add_lun(shost, channel, id, lun, NULL, NULL,
rescan);
return;
}
/*
* Scan LUN 0, if there is some response, scan further. Ideally, we
* would not configure LUN 0 until all LUNs are scanned.
*/
res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev);
res = scsi_probe_and_add_lun(shost, channel, id, 0, &bflags, &sdev,
rescan);
if (res == SCSI_SCAN_LUN_PRESENT) {
if (scsi_report_lun_scan(sdev, bflags) != 0)
if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
/*
* The REPORT LUN did not scan the target,
* do a sequential scan.
*/
scsi_sequential_lun_scan(shost, channel, id, bflags,
res, sdev->scsi_level);
res, sdev->scsi_level, rescan);
} else if (res == SCSI_SCAN_TARGET_PRESENT) {
/*
* There's a target here, but lun 0 is offline so we
......@@ -1116,37 +1147,26 @@ static void scsi_scan_target(struct Scsi_Host *shost, unsigned int channel,
* a default scsi level of SCSI_2
*/
scsi_sequential_lun_scan(shost, channel, id, BLIST_SPARSELUN,
SCSI_SCAN_TARGET_PRESENT, SCSI_2);
SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
}
}
/**
* scsi_scan_host - scan the given adapter
* @shost: adapter to scan
*
* Description:
* Iterate and call scsi_scan_target to scan all possible target id's
* on all possible channels.
**/
void scsi_scan_host(struct Scsi_Host *shost)
static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun, int rescan)
{
uint channel, id, order_id;
uint order_id;
/*
* The sdevscan host, channel, id and lun are filled in as
* needed to scan.
*/
for (channel = 0; channel <= shost->max_channel; channel++) {
/*
* XXX adapter drivers when possible (FCP, iSCSI)
* could modify max_id to match the current max,
* not the absolute max.
*
* XXX add a shost id iterator, so for example,
* the FC ID can be the same as a target id
* without a huge overhead of sparse id's.
*/
if (id == SCAN_WILD_CARD)
for (id = 0; id < shost->max_id; ++id) {
/*
* XXX adapter drivers when possible (FCP, iSCSI)
* could modify max_id to match the current max,
* not the absolute max.
*
* XXX add a shost id iterator, so for example,
* the FC ID can be the same as a target id
* without a huge overhead of sparse id's.
*/
if (shost->reverse_ordering)
/*
* Scan from high to low id.
......@@ -1154,9 +1174,39 @@ void scsi_scan_host(struct Scsi_Host *shost)
order_id = shost->max_id - id - 1;
else
order_id = id;
scsi_scan_target(shost, channel, order_id);
scsi_scan_target(shost, channel, order_id, lun, rescan);
}
}
else
scsi_scan_target(shost, channel, id, lun, rescan);
}
int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, unsigned int lun, int rescan)
{
SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n",
__FUNCTION__, shost->host_no, channel, id, lun));
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id > shost->max_id)) ||
((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
return -EINVAL;
if (channel == SCAN_WILD_CARD)
for (channel = 0; channel <= shost->max_channel; channel++)
scsi_scan_channel(shost, channel, id, lun, rescan);
else
scsi_scan_channel(shost, channel, id, lun, rescan);
return 0;
}
/**
* scsi_scan_host - scan the given adapter
* @shost: adapter to scan
**/
void scsi_scan_host(struct Scsi_Host *shost)
{
scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
SCAN_WILD_CARD, 0);
}
void scsi_forget_host(struct Scsi_Host *shost)
......
......@@ -15,6 +15,43 @@
#include "hosts.h"
#include "scsi_priv.h"
#include "scsi_logging.h"
static int check_set(unsigned int *val, char *src)
{
char *last;
if (strncmp(src, "-", 20) == 0) {
*val = SCAN_WILD_CARD;
} else {
/*
* Doesn't check for int overflow
*/
*val = simple_strtoul(src, &last, 0);
if (*last != '\0')
return 1;
}
return 0;
}
static int scsi_scan(struct Scsi_Host *shost, const char *str)
{
char s1[15], s2[15], s3[15], junk;
unsigned int channel, id, lun;
int res;
res = sscanf(str, "%10s %10s %10s %c", s1, s2, s3, &junk);
if (res != 3)
return -EINVAL;
if (check_set(&channel, s1))
return -EINVAL;
if (check_set(&id, s2))
return -EINVAL;
if (check_set(&lun, s3))
return -EINVAL;
res = scsi_scan_host_selected(shost, channel, id, lun, 1);
return res;
}
/*
* shost_show_function: macro to create an attr function that can be used to
......@@ -39,6 +76,20 @@ static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
/*
* Create the actual show/store functions and data structures.
*/
static ssize_t store_scan(struct class_device *class_dev, const char *buf,
size_t count)
{
struct Scsi_Host *shost = class_to_shost(class_dev);
int res;
res = scsi_scan(shost, buf);
if (res == 0)
res = count;
return res;
};
static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
shost_rd_attr(unique_id, "%u\n");
shost_rd_attr(host_busy, "%hu\n");
shost_rd_attr(cmd_per_lun, "%hd\n");
......@@ -51,33 +102,10 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
&class_device_attr_cmd_per_lun,
&class_device_attr_sg_tablesize,
&class_device_attr_unchecked_isa_dma,
&class_device_attr_scan,
NULL
};
static void scsi_host_cls_release(struct class_device *class_dev)
{
struct Scsi_Host *shost;
shost = class_to_shost(class_dev);
put_device(&shost->shost_gendev);
}
static void scsi_host_dev_release(struct device *dev)
{
struct Scsi_Host *shost;
struct device *parent;
parent = dev->parent;
shost = dev_to_shost(dev);
scsi_free_shost(shost);
put_device(parent);
}
struct class shost_class = {
.name = "scsi_host",
.release = scsi_host_cls_release,
};
static void scsi_device_cls_release(struct class_device *class_dev)
{
struct scsi_device *sdev;
......@@ -113,33 +141,23 @@ struct bus_type scsi_bus_type = {
.match = scsi_bus_match,
};
int scsi_sysfs_register(void)
{
int error;
error = bus_register(&scsi_bus_type);
if (error)
return error;
error = class_register(&shost_class);
if (error)
goto bus_unregister;
error = class_register(&sdev_class);
if (error)
goto class_unregister;
return 0;
if (!error) {
error = class_register(&sdev_class);
if (error)
bus_unregister(&scsi_bus_type);
}
class_unregister:
class_unregister(&shost_class);
bus_unregister:
bus_unregister(&scsi_bus_type);
return error;
}
void scsi_sysfs_unregister(void)
{
class_unregister(&sdev_class);
class_unregister(&shost_class);
bus_unregister(&scsi_bus_type);
}
......@@ -243,6 +261,24 @@ store_rescan_field (struct device *dev, const char *buf, size_t count)
static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field)
static ssize_t sdev_store_delete(struct device *dev, const char *buf,
size_t count)
{
struct scsi_device *sdev = to_scsi_device(dev);
int res = count;
if (sdev->access_count)
/*
* FIXME and scsi_proc.c: racey use of access_count,
* possibly add a new arg to scsi_remove_device.
*/
res = -EBUSY;
else
scsi_remove_device(sdev);
return res;
};
static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
/* Default template for device attributes. May NOT be modified */
static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_device_blocked,
......@@ -255,6 +291,7 @@ static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
&dev_attr_rev,
&dev_attr_online,
&dev_attr_rescan,
&dev_attr_delete,
NULL
};
......@@ -403,20 +440,6 @@ int scsi_register_interface(struct class_interface *intf)
}
void scsi_sysfs_init_host(struct Scsi_Host *shost)
{
device_initialize(&shost->shost_gendev);
snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
shost->host_no);
shost->shost_gendev.release = scsi_host_dev_release;
class_device_initialize(&shost->shost_classdev);
shost->shost_classdev.dev = &shost->shost_gendev;
shost->shost_classdev.class = &shost_class;
snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
shost->host_no);
}
static struct class_device_attribute *class_attr_overridden(
struct class_device_attribute **attrs,
struct class_device_attribute *attr)
......@@ -459,31 +482,16 @@ static int class_attr_add(struct class_device *classdev,
* @shost: scsi host struct to add to subsystem
* @dev: parent struct device pointer
**/
int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev)
int scsi_sysfs_add_host(struct Scsi_Host *shost)
{
int error, i;
if (!shost->shost_gendev.parent)
shost->shost_gendev.parent = dev ? dev : &legacy_bus;
error = device_add(&shost->shost_gendev);
if (error)
return error;
set_bit(SHOST_ADD, &shost->shost_state);
get_device(shost->shost_gendev.parent);
error = class_device_add(&shost->shost_classdev);
if (error)
goto clean_device;
get_device(&shost->shost_gendev);
if (shost->hostt->shost_attrs) {
for (i = 0; shost->hostt->shost_attrs[i]; i++) {
error = class_attr_add(&shost->shost_classdev,
shost->hostt->shost_attrs[i]);
if (error)
goto clean_class;
return error;
}
}
......@@ -493,31 +501,9 @@ int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev)
error = class_device_create_file(&shost->shost_classdev,
scsi_sysfs_shost_attrs[i]);
if (error)
goto clean_class;
return error;
}
}
return error;
clean_class:
class_device_del(&shost->shost_classdev);
clean_device:
device_del(&shost->shost_gendev);
return error;
}
/**
* scsi_sysfs_remove_host - remove scsi host from subsystem
* @shost: scsi host to remove from subsystem
**/
void scsi_sysfs_remove_host(struct Scsi_Host *shost)
{
unsigned long flags;
spin_lock_irqsave(shost->host_lock, flags);
set_bit(SHOST_DEL, &shost->shost_state);
spin_unlock_irqrestore(shost->host_lock, flags);
class_device_unregister(&shost->shost_classdev);
device_del(&shost->shost_gendev);
return 0;
}
......@@ -308,6 +308,8 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[4] = (unsigned char) this_count;
SCpnt->cmnd[5] = 0;
}
SCpnt->request_bufflen = SCpnt->bufflen =
this_count * sdp->sector_size;
/*
* We shouldn't disconnect in the middle of a sector, so with a dumb
......@@ -1353,10 +1355,14 @@ static int sd_remove(struct device *dev)
static void sd_shutdown(struct device *dev)
{
struct scsi_device *sdp = to_scsi_device(dev);
struct scsi_disk *sdkp = dev_get_drvdata(dev);
struct scsi_disk *sdkp;
struct scsi_request *sreq;
int retries, res;
sdkp = dev_get_drvdata(dev);
if (!sdkp)
return; /* this can happen */
if (!sdp->online || !sdkp->WCE)
return;
......
......@@ -340,6 +340,20 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
return 0;
}
{
struct scatterlist *sg = SCpnt->request_buffer;
int i, size = 0;
for (i = 0; i < SCpnt->use_sg; i++)
size += sg[i].length;
if (size != SCpnt->request_bufflen && SCpnt->use_sg) {
printk(KERN_ERR "sr: mismatch count %d, bytes %d\n",
size, SCpnt->request_bufflen);
if (SCpnt->request_bufflen > size)
SCpnt->request_bufflen = SCpnt->bufflen = size;
}
}
/*
* request doesn't start on hw block boundary, add scatter pads
*/
......@@ -361,8 +375,11 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[1] = 0;
block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
if (this_count > 0xffff)
if (this_count > 0xffff) {
this_count = 0xffff;
SCpnt->request_bufflen = SCpnt->bufflen =
this_count * s_size;
}
SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
......@@ -390,18 +407,6 @@ static int sr_init_command(struct scsi_cmnd * SCpnt)
*/
SCpnt->done = rw_intr;
{
struct scatterlist *sg = SCpnt->request_buffer;
int i, size = 0;
for (i = 0; i < SCpnt->use_sg; i++)
size += sg[i].length;
if (size != SCpnt->request_bufflen && SCpnt->use_sg) {
printk("sr: mismatch count %d, bytes %d\n", size, SCpnt->request_bufflen);
SCpnt->request_bufflen = size;
}
}
/*
* This indicates that the command is ready from our end to be
* queued.
......
......@@ -2029,7 +2029,7 @@ sym_attach (struct scsi_host_template *tpnt, int unit, sym_device *dev)
printf_info("%s: giving up ...\n", sym_name(np));
if (np)
sym_free_resources(np);
scsi_unregister(instance);
scsi_host_put(instance);
return -1;
}
......
......@@ -5942,14 +5942,7 @@ int sym_hcb_attach(hcb_p np, struct sym_fw *fw)
*/
return 0;
/*
* We have failed.
* We will try to free all the resources we have
* allocated, but if we are a boot device, this
* will not help that much.;)
*/
attach_failed:
sym_hcb_free(np);
return -ENXIO;
}
......
......@@ -135,11 +135,9 @@ zalon_scsi_callback(struct parisc_device *dev)
if(!host)
goto fail;
strlcpy(dev->dev.name, "zalon7xx", sizeof(dev->dev.name));
if(request_irq(irq, ncr53c8xx_intr, SA_SHIRQ, dev->dev.name, host)) {
if(request_irq(irq, ncr53c8xx_intr, SA_SHIRQ, dev->dev.bus_id, host)) {
printk(KERN_ERR "%s: irq problem with %d, detaching\n ",
dev->dev.name, irq);
dev->dev.bus_id, irq);
goto fail;
}
......
......@@ -16,6 +16,8 @@
*/
#include <linux/types.h>
/*
* SCSI command lengths
*/
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment