Implement multichannel support in the way each channel is seen by SCST

as separate HBA.


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@325 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Stanislaw Gruszka
2008-04-04 11:48:28 +00:00
parent be3bbaa220
commit 16717c2bc9

View File

@@ -140,29 +140,34 @@
#endif
typedef struct bus bus_t;
typedef struct bus_chan bus_chan_t;
typedef struct initiator ini_t;
struct initiator {
ini_t * ini_next;
bus_t * ini_bus; /* backpointer to containing bus */
uint64_t ini_iid; /* initiator identifier */
struct scst_session * ini_scst_sess; /* sesson established by this remote initiator */
};
#define HASH_WIDTH 16
#define INI_HASH_LISTP(busp, ini_id) busp->list[ini_id & (HASH_WIDTH - 1)]
#define INI_HASH_LISTP(bc, ini_id) bc->list[ini_id & (HASH_WIDTH - 1)]
struct bus {
hba_register_t h; /* must be first */
struct bus_chan {
ini_t * list[HASH_WIDTH]; /* hash list of known initiators */
struct scst_tgt * scst_tgt;
hba_register_t * reg_hp; /* helpers for registration / unregistration */
hba_register_t * unreg_hp;
unsigned long enable; /* is target mode enabled in low level driver, one bit per channel */
struct tasklet_struct tasklet;
spinlock_t tmds_lock;
tmd_cmd_t * tmds_front;
tmd_cmd_t * tmds_tail;
struct tasklet_struct tasklet;
struct scst_tgt * scst_tgt;
int enable; /* is target mode enabled in low level driver */
bus_t * bus; /* back pointer */
};
struct bus {
hba_register_t h; /* must be first */
int need_reg; /* helpers for registration / unregistration */
hba_register_t * unreg_hp;
bus_chan_t * bchan; /* channels */
};
#define SDprintk if (debug) printk
@@ -178,13 +183,13 @@ static void scsi_target_handler(qact_e, void *);
static __inline bus_t *bus_from_tmd(tmd_cmd_t *);
static __inline bus_t *bus_from_name(const char *);
static __inline ini_t *ini_from_tmd(bus_t *, tmd_cmd_t *);
static __inline ini_t *ini_from_notify(bus_t *, tmd_notify_t *);
static __inline ini_t *ini_from_tmd(bus_chan_t *, tmd_cmd_t *);
static __inline ini_t *ini_from_notify(bus_chan_t *, tmd_notify_t *);
static void scsi_target_start_cmd(tmd_cmd_t *, int);
static void scsi_target_done_cmd(tmd_cmd_t *, int);
static int scsi_target_thread(void *);
static int scsi_target_enadis(bus_t *, int, int);
static int scsi_target_enadis(bus_chan_t *, int);
static bus_t busses[MAX_BUS];
@@ -249,9 +254,9 @@ bus_from_name(const char *name)
}
static __inline ini_t *
ini_from_tmd(bus_t *bp, tmd_cmd_t *tmd)
ini_from_tmd(bus_chan_t *bc, tmd_cmd_t *tmd)
{
ini_t *ptr = INI_HASH_LISTP(bp, tmd->cd_iid);
ini_t *ptr = INI_HASH_LISTP(bc, tmd->cd_iid);
if (ptr) {
do {
if (ptr->ini_iid == tmd->cd_iid) {
@@ -263,7 +268,7 @@ ini_from_tmd(bus_t *bp, tmd_cmd_t *tmd)
}
static __inline ini_t *
ini_from_notify(bus_t *bp, tmd_notify_t *np)
ini_from_notify(bus_chan_t *bc, tmd_notify_t *np)
{
ini_t *ptr = NULL;
int i;
@@ -271,13 +276,13 @@ ini_from_notify(bus_t *bp, tmd_notify_t *np)
if (np->nt_iid == INI_ANY) {
/* SCST task mgmt need to be related with some session */
for (i = 0; i < HASH_WIDTH; i++) {
ini_t *ptr = bp->list[i];
ini_t *ptr = bc->list[i];
if (ptr) {
return (ptr);
}
}
} else {
ptr = INI_HASH_LISTP(bp, np->nt_iid);
ptr = INI_HASH_LISTP(bc, np->nt_iid);
if (ptr) {
do {
if (ptr->ini_iid == np->nt_iid) {
@@ -309,7 +314,7 @@ bus_from_notify(tmd_notify_t *np)
*/
static ini_t *
alloc_ini(bus_t *bp, uint64_t iid)
alloc_ini(bus_chan_t *bc, uint64_t iid)
{
ini_t *nptr;
char ini_name[24];
@@ -323,10 +328,10 @@ alloc_ini(bus_t *bp, uint64_t iid)
#define GET(byte) (uint8_t) ((iid >> 8*byte) & 0xff)
snprintf(ini_name, sizeof(ini_name), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
GET(7), GET(6), GET(5) , GET(4), GET(3), GET(2), GET(1), GET(0));
GET(7), GET(6), GET(5) , GET(4), GET(3), GET(2), GET(1), GET(0));
#undef GET
nptr->ini_scst_sess = scst_register_session(bp->scst_tgt, 0, ini_name, NULL, NULL);
nptr->ini_scst_sess = scst_register_session(bc->scst_tgt, 0, ini_name, NULL, NULL);
if (!nptr->ini_scst_sess) {
Eprintk("cannot register SCST session\n");
kfree(nptr);
@@ -337,12 +342,11 @@ alloc_ini(bus_t *bp, uint64_t iid)
}
static void
add_ini(bus_t *bp, uint64_t iid, ini_t *nptr)
add_ini(bus_chan_t *bc, uint64_t iid, ini_t *nptr)
{
ini_t **ptrlptr = &INI_HASH_LISTP(bp, iid);
ini_t **ptrlptr = &INI_HASH_LISTP(bc, iid);
nptr->ini_iid = iid;
nptr->ini_bus = (struct bus *) bp;
nptr->ini_next = *ptrlptr;
*ptrlptr = nptr;
@@ -358,29 +362,30 @@ free_ini(ini_t *ini)
static void
tasklet_rx_cmds(unsigned long data)
{
bus_t *bp = (bus_t *) data;
bus_chan_t *bc = (bus_chan_t *) data;
bus_t *bp = bc->bus;
ini_t *ini;
tmd_cmd_t *tmd;
tmd_xact_t *xact;
struct scst_cmd *scst_cmd;
rx_loop:
spin_lock_irq(&bp->tmds_lock);
tmd = bp->tmds_front;
spin_lock_irq(&bc->tmds_lock);
tmd = bc->tmds_front;
if (tmd == NULL || tmd->cd_ini == NULL) {
spin_unlock_irq(&bp->tmds_lock);
spin_unlock_irq(&bc->tmds_lock);
return;
}
/* remove from queue */
bp->tmds_front = tmd->cd_hnext;
if (bp->tmds_front == NULL) {
bp->tmds_tail = NULL;
/* remove from queue */
bc->tmds_front = tmd->cd_hnext;
if (bc->tmds_front == NULL) {
bc->tmds_tail = NULL;
}
/* free command if aborted */
if (tmd->cd_flags & CDF_PRIVATE_ABORTED) {
spin_unlock_irq(&bp->tmds_lock);
spin_unlock_irq(&bc->tmds_lock);
SDprintk("%s: ABORTED TMD_FIN[%llx]\n", __FUNCTION__, tmd->cd_tagval);
(*bp->h.r_action)(QIN_TMD_FIN, tmd);
goto rx_loop;
@@ -389,7 +394,7 @@ rx_loop:
ini = tmd->cd_ini;
scst_cmd = scst_rx_cmd(ini->ini_scst_sess, tmd->cd_lun, sizeof(tmd->cd_lun), tmd->cd_cdb, sizeof(tmd->cd_cdb), 1);
if (scst_cmd == NULL) {
spin_unlock_irq(&bp->tmds_lock);
spin_unlock_irq(&bc->tmds_lock);
tmd->cd_scsi_status = SCSI_BUSY;
xact = &tmd->cd_xact;
xact->td_hflags |= TDFH_STSVALID;
@@ -397,7 +402,7 @@ rx_loop:
xact->td_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, xact);
goto rx_loop;
}
}
scst_cmd_set_tgt_priv(scst_cmd, tmd);
scst_cmd_set_tag(scst_cmd, tmd->cd_tagval);
@@ -448,7 +453,7 @@ rx_loop:
scst_cmd_set_expected(scst_cmd, dir, len);
}
scst_cmd_init_done(scst_cmd, SCST_CONTEXT_TASKLET);
spin_unlock_irq(&bp->tmds_lock);
spin_unlock_irq(&bc->tmds_lock);
goto rx_loop;
}
@@ -458,36 +463,38 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
{
unsigned long flags;
bus_t *bp;
bus_chan_t *bc;
/* first, find the bus */
spin_lock_irqsave(&scsi_target_lock, flags);
bp = bus_from_tmd(tmd);
if (bp == NULL || bp->scst_tgt == NULL) {
if (unlikely(bp == NULL || bp->bchan == NULL)) {
spin_unlock_irqrestore(&scsi_target_lock, flags);
Eprintk("cannot find %s for incoming command\n", (bp == NULL) ? "bus" : "SCST target");
Eprintk("cannot find %s for incoming command\n", (bp == NULL) ? "bus" : "channel");
return;
}
spin_unlock_irqrestore(&scsi_target_lock, flags);
tmd->cd_bus = bp;
tmd->cd_hnext = NULL;
bc = &bp->bchan[tmd->cd_channel];
/* then, add commands to queue */
spin_lock_irqsave(&bp->tmds_lock, flags);
tmd->cd_ini = ini_from_tmd(bp, tmd);
if (bp->tmds_front == NULL) {
bp->tmds_front = tmd;
spin_lock_irqsave(&bc->tmds_lock, flags);
tmd->cd_ini = ini_from_tmd(bc, tmd);
if (bc->tmds_front == NULL) {
bc->tmds_front = tmd;
} else {
bp->tmds_tail->cd_hnext = tmd;
bc->tmds_tail->cd_hnext = tmd;
}
bp->tmds_tail = tmd;
spin_unlock_irqrestore(&bp->tmds_lock, flags);
bc->tmds_tail = tmd;
spin_unlock_irqrestore(&bc->tmds_lock, flags);
/* finally, shedule proper action */
if (unlikely(tmd->cd_ini == NULL)) {
schedule_scsi_thread(SF_ADD_INITIATORS);
} else {
tasklet_schedule(&bp->tasklet);
tasklet_schedule(&bc->tasklet);
}
/* old bug warrning */
@@ -497,15 +504,74 @@ scsi_target_start_cmd(tmd_cmd_t *tmd, int from_intr)
}
static void
add_initiators(void)
bus_chan_add_initiators(bus_t *bp, int chan)
{
bus_t *bp;
bus_chan_t *bc = &bp->bchan[chan];
ini_t *ini;
tmd_cmd_t *tmd;
tmd_cmd_t *prev_tmd = NULL;
tmd_xact_t *xact;
/* check registered busses */
/* iterate over queue and find any commands not assigned to initiator */
spin_lock_irq(&bc->tmds_lock);
tmd = bc->tmds_front;
while (tmd) {
BUG_ON(tmd->cd_channel != chan);
if (tmd->cd_ini != NULL) {
/* ini assigned, go to the next command */
prev_tmd = tmd;
tmd = tmd->cd_hnext;
} else {
/* check if proper initiator exist already */
ini = ini_from_tmd(bc, tmd);
if (ini != NULL) {
tmd->cd_ini = ini;
} else {
spin_unlock_irq(&bc->tmds_lock);
ini = alloc_ini(bc, tmd->cd_iid);
spin_lock_irq(&bc->tmds_lock);
if (ini != NULL) {
tmd->cd_ini = ini;
add_ini(bc, tmd->cd_iid, ini);
} else {
/* fail to alloc initiator, remove from queue and send busy */
if (prev_tmd == NULL) {
bc->tmds_front = tmd->cd_hnext;
} else {
prev_tmd->cd_hnext = tmd->cd_hnext;
}
if (bc->tmds_tail == tmd) {
bc->tmds_tail = prev_tmd;
}
spin_unlock_irq(&bc->tmds_lock);
tmd->cd_scsi_status = SCSI_BUSY;
xact = &tmd->cd_xact;
xact->td_hflags |= TDFH_STSVALID;
xact->td_hflags &= ~TDFH_DATA_MASK;
xact->td_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, xact);
spin_lock_irq(&bc->tmds_lock);
/* iterate to the next command, previous is not changed */
tmd = tmd->cd_hnext;
}
}
}
}
spin_unlock_irq(&bc->tmds_lock);
/* now we can run queue and pass commands to scst */
tasklet_schedule(&bc->tasklet);
}
static void
bus_add_initiators(void)
{
bus_t *bp;
int chan;
for (bp = busses; bp < &busses[MAX_BUS]; bp++) {
spin_lock_irq(&scsi_target_lock);
if (bp->h.r_action == NULL) {
@@ -513,56 +579,10 @@ add_initiators(void)
continue;
}
spin_unlock_irq(&scsi_target_lock);
/* iterate over queue and find any commands not assigned to initiator */
spin_lock_irq(&bp->tmds_lock);
tmd = bp->tmds_front;
while (tmd) {
if (tmd->cd_ini != NULL) {
/* ini assigned, go to the next command */
prev_tmd = tmd;
tmd = tmd->cd_hnext;
} else {
/* check if proper initiator exist already */
ini = ini_from_tmd(bp, tmd);
if (ini != NULL) {
tmd->cd_ini = ini;
} else {
spin_unlock_irq(&bp->tmds_lock);
ini = alloc_ini(bp, tmd->cd_iid);
spin_lock_irq(&bp->tmds_lock);
if (ini != NULL) {
tmd->cd_ini = ini;
add_ini(bp, tmd->cd_iid, ini);
} else {
/* fail to alloc initiator, remove from queue and send busy */
if (prev_tmd == NULL) {
bp->tmds_front = tmd->cd_hnext;
} else {
prev_tmd->cd_hnext = tmd->cd_hnext;
}
if (bp->tmds_tail == tmd) {
bp->tmds_tail = prev_tmd;
}
// FIXME: spin unlock/lock ?
tmd->cd_scsi_status = SCSI_BUSY;
xact = &tmd->cd_xact;
xact->td_hflags |= TDFH_STSVALID;
xact->td_hflags &= ~TDFH_DATA_MASK;
xact->td_xfrlen = 0;
(*bp->h.r_action)(QIN_TMD_CONT, xact);
/* iterate to the next command, previous is not changed */
tmd = tmd->cd_hnext;
}
}
}
for (chan = 0; chan < bp->h.r_nchannels; chan++) {
bus_chan_add_initiators(bp, chan);
}
spin_unlock_irq(&bp->tmds_lock);
/* now we can run queue and pass commands to scst */
tasklet_schedule(&bp->tasklet);
}
}
@@ -626,40 +646,41 @@ scsi_target_done_cmd(tmd_cmd_t *tmd, int from_intr)
}
static int
abort_task(bus_t *bp, uint64_t tagval)
abort_task(bus_chan_t *bc, uint64_t tagval)
{
unsigned long flags;
tmd_cmd_t *tmd;
spin_lock_irqsave(&bp->tmds_lock, flags);
for (tmd = bp->tmds_front; tmd; tmd = tmd->cd_hnext) {
spin_lock_irqsave(&bc->tmds_lock, flags);
for (tmd = bc->tmds_front; tmd; tmd = tmd->cd_hnext) {
if (tmd->cd_tagval == tagval) {
tmd->cd_flags |= CDF_PRIVATE_ABORTED;
spin_unlock_irqrestore(&bp->tmds_lock, flags);
spin_unlock_irqrestore(&bc->tmds_lock, flags);
return 1;
}
}
spin_unlock_irqrestore(&bp->tmds_lock, flags);
spin_unlock_irqrestore(&bc->tmds_lock, flags);
return 0;
}
static void
abort_all_tasks(bus_t *bp)
abort_all_tasks(bus_chan_t *bc)
{
unsigned long flags;
tmd_cmd_t *tmd;
spin_lock_irqsave(&bp->tmds_lock, flags);
for (tmd = bp->tmds_front; tmd; tmd = tmd->cd_hnext) {
spin_lock_irqsave(&bc->tmds_lock, flags);
for (tmd = bc->tmds_front; tmd; tmd = tmd->cd_hnext) {
tmd->cd_flags |= CDF_PRIVATE_ABORTED;
}
spin_unlock_irqrestore(&bp->tmds_lock, flags);
spin_unlock_irqrestore(&bc->tmds_lock, flags);
}
static void
scsi_target_notify(tmd_notify_t *np)
{
bus_t *bp;
bus_chan_t *bc;
ini_t *ini;
int fn;
uint16_t lun;
@@ -674,21 +695,22 @@ scsi_target_notify(tmd_notify_t *np)
spin_lock_irqsave(&scsi_target_lock, flags);
bp = bus_from_notify(np);
if (bp == NULL) {
if (unlikely(bp == NULL || bp->bchan == NULL)) {
spin_unlock_irqrestore(&scsi_target_lock, flags);
Eprintk("TMD_NOTIFY cannot find bus\n");
Eprintk("TMD_NOTIFY cannot find %s\n", bp == NULL ? "bus" : "channel");
return;
}
spin_unlock_irqrestore(&scsi_target_lock, flags);
SDprintk("scsi_target: MGT code %x from %s%d iid 0x%016llx\n", np->nt_ncode, bp->h.r_name, bp->h.r_inst, np->nt_iid);
spin_lock_irqsave(&bp->tmds_lock, flags);
ini = ini_from_notify(bp, np);
spin_unlock_irqrestore(&bp->tmds_lock, flags);
bc = &bp->bchan[np->nt_channel];
spin_lock_irqsave(&bc->tmds_lock, flags);
ini = ini_from_notify(bc, np);
spin_unlock_irqrestore(&bc->tmds_lock, flags);
switch (np->nt_ncode) {
case NT_ABORT_TASK:
if (abort_task(bp, np->nt_tagval)) {
if (abort_task(bc, np->nt_tagval)) {
SDprintk("TMD_NOTIFY abort task [%llx]\n", np->nt_tagval);
(*bp->h.r_action) (QIN_NOTIFY_ACK, np);
return;
@@ -701,11 +723,11 @@ scsi_target_notify(tmd_notify_t *np)
scst_rx_mgmt_fn_tag(ini->ini_scst_sess, SCST_ABORT_TASK, np->nt_tagval, 1, np);
return;
case NT_ABORT_TASK_SET:
abort_all_tasks(bp);
abort_all_tasks(bc);
fn = SCST_ABORT_TASK_SET;
break;
case NT_CLEAR_TASK_SET:
abort_all_tasks(bp);
abort_all_tasks(bc);
fn = SCST_CLEAR_TASK_SET;
break;
case NT_CLEAR_ACA: // FIXME: does we support this?
@@ -755,6 +777,7 @@ scsi_target_handler(qact_e action, void *arg)
case QOUT_HBA_REG:
{
hba_register_t *hp;
spin_lock_irqsave(&scsi_target_lock, flags);
for (bp = busses; bp < &busses[MAX_BUS]; bp++) {
if (bp->h.r_action == NULL) {
@@ -772,14 +795,8 @@ scsi_target_handler(qact_e action, void *arg)
Eprintk("version mismatch - compiled with %d, got %d\n", QR_VERSION, hp->r_version);
break;
}
/* enable bitmap size constrained */
if (hp->r_nchannels > 32) {
spin_unlock_irqrestore(&scsi_target_lock, flags);
Eprintk("isp_scst not support more than 32 channels\n");
break;
}
bp->h = *hp;
bp->reg_hp = hp;
bp->need_reg = 1;
spin_unlock_irqrestore(&scsi_target_lock, flags);
schedule_scsi_thread(SF_REGISTER_SCST);
break;
@@ -877,7 +894,7 @@ scsi_target_thread(void *arg)
register_scst();
}
if (test_and_clear_bit(SF_ADD_INITIATORS, &schedule_flags)) {
add_initiators();
bus_add_initiators();
}
if (test_and_clear_bit(SF_UNREGISTER_SCST, &schedule_flags)) {
unregister_scst();
@@ -889,18 +906,21 @@ scsi_target_thread(void *arg)
}
static int
scsi_target_enadis(bus_t *bp, int chan, int en)
scsi_target_enadis(bus_chan_t *bc, int en)
{
DECLARE_MUTEX_LOCKED(rsem);
enadis_t ec;
info_t info;
int old_en, err;
int chan, err;
bus_t *bp;
old_en = test_bit(chan, &bp->enable);
if (old_en == en) {
if (en == bc->enable) {
return (0);
}
bp = bc->bus;
chan = (bc - bp->bchan) / sizeof (bus_chan_t);
memset(&info, 0, sizeof (info));
info.i_identity = bp->h.r_identity;
info.i_channel = chan;
@@ -914,7 +934,6 @@ scsi_target_enadis(bus_t *bp, int chan, int en)
ec.en_hba = bp->h.r_identity;
ec.en_chan = chan;
if (bp->h.r_type == R_FC) {
SDprintk("%s: ANY LUN acceptable\n", __FUNCTION__);
ec.en_lun = LUN_ANY;
} else {
ec.en_lun = 0;
@@ -923,12 +942,12 @@ scsi_target_enadis(bus_t *bp, int chan, int en)
(*bp->h.r_action)(en ? QIN_ENABLE : QIN_DISABLE, &ec);
down(&rsem);
if (ec.en_error) {
err = ec.en_error;
goto failed;
goto failed;
}
change_bit(chan, &bp->enable);
bc->enable = en;
return (0);
failed:
@@ -1070,46 +1089,35 @@ isp_task_mgmt_fn_done(struct scst_mgmt_cmd *mgmt_cmd)
static int
isp_read_proc(struct seq_file *seq, struct scst_tgt *tgt)
{
bus_t *bp;
int chan;
bus_chan_t *bc;
bp = tgt->tgt_priv;
if (!bp) {
bc = tgt->tgt_priv;
if (!bc) {
return (-ENODEV);
}
for (chan = 0; chan < bp->h.r_nchannels; chan++) {
seq_printf(seq, "%d:%d\n", chan, test_bit(chan, &bp->enable) ? 1 : 0);
}
seq_printf(seq, "%d\n", bc->enable);
return (0);
}
static int
isp_write_proc(char *buf, char **start, off_t offset, int len, int *eof, struct scst_tgt *tgt)
{
bus_t *bp;
char *end = buf + len;
int ret, en, chan;
bus_chan_t *bc;
int ret, en;
bp = tgt->tgt_priv;
if (!bp) {
bc = tgt->tgt_priv;
if (!bc) {
return (-ENODEV);
}
if (len < 3) {
return (-EINVAL);
}
chan = simple_strtoul(buf, &buf, 0);
if (chan < 0 || chan > bp->h.r_nchannels || *buf != ':') {
return (-EINVAL);
}
buf++;
if (buf >= end) {
return (-EINVAL);
}
en = buf[0] - '0';
if (en < 0 || en > 1) {
return (-EINVAL);
}
ret = scsi_target_enadis(bp, chan, en);
ret = scsi_target_enadis(bc, en);
if (ret < 0) {
return (ret);
}
@@ -1141,49 +1149,75 @@ static struct scst_tgt_template isp_tgt_template =
};
static void
register_hba(bus_t *bp, hba_register_t *reg_hp)
register_hba(bus_t *bp)
{
char name[32];
info_t info;
int chan;
bus_chan_t *bchan, *bc;
struct scst_tgt *scst_tgt;
bchan = kzalloc(bp->h.r_nchannels * sizeof(bus_chan_t), GFP_KERNEL);
if (bchan == NULL) {
Eprintk("cannot allocate %d channels for %s%d\n", bp->h.r_nchannels, bp->h.r_name, bp->h.r_inst);
goto err_free_bus;
}
info.i_identity = bp->h.r_identity;
if (bp->h.r_type == R_FC) {
info.i_type = I_FC;
} else {
info.i_type = I_SPI;
}
info.i_channel = 0;
(*bp->h.r_action)(QIN_GETINFO, &info);
if (info.i_error) {
Eprintk("cannot get device name from %s%d!\n", bp->h.r_name, bp->h.r_inst);
goto err_free_bus;
for (chan = 0; chan < bp->h.r_nchannels; chan++) {
info.i_channel = chan;
(*bp->h.r_action)(QIN_GETINFO, &info);
if (info.i_error) {
Eprintk("cannot get device name from %s%d!\n", bp->h.r_name, bp->h.r_inst);
goto err_free_chan;
}
if (info.i_type == I_FC) {
#define GET(byte) (uint8_t) ((info.i_id.fc.wwpn >> 8*byte) & 0xff)
snprintf(name, sizeof(name), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
GET(7), GET(6), GET(5) , GET(4), GET(3), GET(2), GET(1), GET(0));
#undef GET
} else { // SPI
#define GET(byte) (uint8_t) ((info.i_id.spi.iid >> 8*byte) & 0xff)
snprintf(name, sizeof(name), "%02x:%02x:%02x:%02x", GET(3), GET(2), GET(1), GET(0));
#undef GET
}
scst_tgt = scst_register(&isp_tgt_template, name);
if (scst_tgt) {
Eprintk("cannot register scst device %s for %s%d\n", name, bp->h.r_name, bp->h.r_inst);
goto err_free_chan;
}
bc = &bchan[chan];
spin_lock_init(&bc->tmds_lock);
tasklet_init(&bc->tasklet, tasklet_rx_cmds, (unsigned long) bc);
bc->bus = bp;
bc->scst_tgt = scst_tgt;
scst_tgt->tgt_priv = bc;
}
if (info.i_type == I_FC) {
#define GET(byte) (uint8_t) ((info.i_id.fc.wwpn >> 8*byte) & 0xff)
snprintf(name, sizeof(name), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
GET(7), GET(6), GET(5) , GET(4), GET(3), GET(2), GET(1), GET(0));
#undef GET
} else { // SPI
#define GET(byte) (uint8_t) ((info.i_id.spi.iid >> 8*byte) & 0xff)
snprintf(name, sizeof(name), "%02x:%02x:%02x:%02x", GET(3), GET(2), GET(1), GET(0));
#undef GET
}
scst_tgt = scst_register(&isp_tgt_template, name);
if (scst_tgt) {
Eprintk("cannot register scst device %s for %s%d\n", name, bp->h.r_name, bp->h.r_inst);
goto err_free_bus;
}
spin_lock_irq(&scsi_target_lock);
bp->scst_tgt = scst_tgt;
bp->scst_tgt->tgt_priv = bp;
bp->bchan = bchan;
spin_unlock_irq(&scsi_target_lock);
Iprintk("registering %s%d\n", reg_hp->r_name, reg_hp->r_inst);
(reg_hp->r_action)(QIN_HBA_REG, reg_hp);
Iprintk("registering %s%d\n", bp->h.r_name, bp->h.r_inst);
(bp->h.r_action)(QIN_HBA_REG, &bp->h);
return;
err_free_chan:
for ( ; chan >= 0; chan--) {
if (bchan[chan].scst_tgt) {
scst_unregister(bchan[chan].scst_tgt);
}
}
kfree(bchan);
err_free_bus:
spin_lock_irq(&scsi_target_lock);
@@ -1194,30 +1228,31 @@ err_free_bus:
static void
unregister_hba(bus_t *bp, hba_register_t *unreg_hp)
{
int i;
/* remove existing initiators */
for (i = 0; i < HASH_WIDTH; i++) {
ini_t *ini_next;
ini_t *ptr = bp->list[i];
if (ptr) {
do {
ini_next = ptr->ini_next;
free_ini(ptr);
} while ((ptr = ini_next) != NULL);
}
}
if (bp->scst_tgt) {
scst_unregister(bp->scst_tgt);
}
int i, chan;
/* it's safe now to reinit bp */
spin_lock_irq(&scsi_target_lock);
memset(bp, 0, sizeof(bus_t));
spin_lock_init(&bp->tmds_lock);
tasklet_init(&bp->tasklet, tasklet_rx_cmds, (unsigned long) bp);
spin_unlock_irq(&scsi_target_lock);
for (chan = 0; chan < bp->h.r_nchannels; chan++) {
/* remove existing initiators */
for (i = 0; i < HASH_WIDTH; i++) {
ini_t *ini_next;
ini_t *ptr = bp->bchan[chan].list[i];
if (ptr) {
do {
ini_next = ptr->ini_next;
free_ini(ptr);
} while ((ptr = ini_next) != NULL);
}
}
if (bp->bchan[chan].scst_tgt) {
scst_unregister(bp->bchan[chan].scst_tgt);
}
/* it's safe now to reinit bp */
kfree(bp->bchan);
spin_lock_irq(&scsi_target_lock);
memset(bp, 0, sizeof(bus_t));
spin_unlock_irq(&scsi_target_lock);
}
Iprintk("unregistering %s%d\n", unreg_hp->r_name, unreg_hp->r_inst);
(unreg_hp->r_action)(QIN_HBA_UNREG, unreg_hp);
@@ -1228,19 +1263,17 @@ static void
register_scst(void)
{
bus_t *bp;
hba_register_t *reg_hp;
for (bp = busses; bp < &busses[MAX_BUS]; bp++) {
spin_lock_irq(&scsi_target_lock);
if (bp->h.r_action == NULL || bp->reg_hp == NULL) {
if (bp->h.r_action == NULL || bp->need_reg == 0) {
spin_unlock_irq(&scsi_target_lock);
continue;
}
reg_hp = bp->reg_hp;
bp->reg_hp = NULL;
bp->need_reg = 0;
spin_unlock_irq(&scsi_target_lock);
register_hba(bp, reg_hp);
register_hba(bp);
}
}
@@ -1290,13 +1323,7 @@ stop_scsi_target_thread(void)
int init_module(void)
{
int ret;
bus_t *bp;
for (bp = busses; bp < &busses[MAX_BUS]; bp++) {
tasklet_init(&bp->tasklet, tasklet_rx_cmds, (unsigned long) bp);
spin_lock_init(&bp->tmds_lock);
}
spin_lock_init(&scsi_target_lock);
start_scsi_target_thread();