From b0a070ce29c7f901038f9cfb6bfef9247d44075f Mon Sep 17 00:00:00 2001 From: scottl Date: Tue, 25 Nov 2008 07:17:11 +0000 Subject: Big update to the iSCSI initiator code. Highlights include IPv6 support, many bugs fixes, many more performance improvements. Submitted by: Danny Braniss M sbin/iscontrol/iscsi.conf.5 M sbin/iscontrol/iscontrol.8 M sbin/iscontrol/iscontrol.h M sbin/iscontrol/config.c M sbin/iscontrol/fsm.c M sbin/iscontrol/login.c M sbin/iscontrol/pdu.c M sbin/iscontrol/misc.c M sbin/iscontrol/auth_subr.c M sbin/iscontrol/iscontrol.c M sys/dev/iscsi/initiator/isc_cam.c M sys/dev/iscsi/initiator/iscsi.h M sys/dev/iscsi/initiator/isc_soc.c M sys/dev/iscsi/initiator/iscsi_subr.c M sys/dev/iscsi/initiator/iscsivar.h M sys/dev/iscsi/initiator/isc_subr.c M sys/dev/iscsi/initiator/iscsi.c M sys/dev/iscsi/initiator/isc_sm.c --- sbin/iscontrol/auth_subr.c | 3 +- sbin/iscontrol/config.c | 2 +- sbin/iscontrol/fsm.c | 97 +++++++----- sbin/iscontrol/iscontrol.8 | 2 +- sbin/iscontrol/iscontrol.c | 15 +- sbin/iscontrol/iscontrol.h | 9 +- sbin/iscontrol/iscsi.conf.5 | 2 +- sbin/iscontrol/login.c | 15 +- sbin/iscontrol/misc.c | 2 +- sbin/iscontrol/pdu.c | 3 +- sys/dev/iscsi/initiator/isc_cam.c | 36 +++-- sys/dev/iscsi/initiator/isc_sm.c | 136 ++++++++++------- sys/dev/iscsi/initiator/isc_soc.c | 282 +++++++++++++++++++++-------------- sys/dev/iscsi/initiator/isc_subr.c | 4 +- sys/dev/iscsi/initiator/iscsi.c | 126 +++++++++++++--- sys/dev/iscsi/initiator/iscsi.h | 99 +++++++++++- sys/dev/iscsi/initiator/iscsi_subr.c | 69 +++++++-- sys/dev/iscsi/initiator/iscsivar.h | 63 +++++--- 18 files changed, 675 insertions(+), 290 deletions(-) diff --git a/sbin/iscontrol/auth_subr.c b/sbin/iscontrol/auth_subr.c index 8381687..06c0ee5 100644 --- a/sbin/iscontrol/auth_subr.c +++ b/sbin/iscontrol/auth_subr.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -54,7 +54,6 @@ __FBSDID("$FreeBSD$"); #include "iscsi.h" #include "iscontrol.h" -#include "pdu.h" static int chapMD5(char id, char *cp, char *chapSecret, unsigned char *digest) diff --git a/sbin/iscontrol/config.c b/sbin/iscontrol/config.c index 409ed2c..d6d250d 100644 --- a/sbin/iscontrol/config.c +++ b/sbin/iscontrol/config.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sbin/iscontrol/fsm.c b/sbin/iscontrol/fsm.c index 6a1c529..443ebca 100644 --- a/sbin/iscontrol/fsm.c +++ b/sbin/iscontrol/fsm.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,7 +58,6 @@ __FBSDID("$FreeBSD$"); #include "iscsi.h" #include "iscontrol.h" -#include "pdu.h" typedef enum { T1 = 1, @@ -66,38 +65,40 @@ typedef enum { T10, T11, T12, T13, T14, T15, T16, T18 } trans_t; +/* + | now supports IPV6 + | thanks to: + | Hajimu UMEMOTO @ Internet Mutual Aid Society Yokohama, Japan + | ume@mahoroba.org ume@{,jp.}FreeBSD.org + | http://www.imasy.org/~ume/ + */ static trans_t tcpConnect(isess_t *sess) { isc_opt_t *op = sess->op; - int val, sv_errno; - struct addrinfo *res, hints; - struct sockaddr_in sn; - struct in_addr ipn; - time_t sec; + int val, sv_errno, soc; + struct addrinfo *res, *res0, hints; + char pbuf[10]; debug_called(3); if(sess->flags & (SESS_RECONNECT|SESS_REDIRECT)) { syslog(LOG_INFO, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected"); - debug(3, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected"); + debug(1, "%s", (sess->flags & SESS_RECONNECT) ? "Reconnect": "Redirected"); shutdown(sess->soc, SHUT_RDWR); //close(sess->soc); - sleep(5); // XXX: actually should be ? sess->soc = -1; sess->flags &= ~SESS_CONNECTED; if(sess->flags & SESS_REDIRECT) { - if(sess->redirect_cnt++ > MAXREDIRECTS) { - syslog(LOG_WARNING, "too many redirects > %d", MAXREDIRECTS); - return 0; - } + sess->redirect_cnt++; sess->flags |= SESS_RECONNECT; - } - if((sess->flags & SESS_RECONNECT) == 0) - return 0; - + } else + sleep(2); // XXX: actually should be ? +#ifdef notyet + { + time_t sec; // make sure we are not in a loop // XXX: this code has to be tested sec = time(0) - sess->reconnect_time; @@ -117,41 +118,46 @@ tcpConnect(isess_t *sess) return 0; } } - sess->reconnect_cnt++; - // sess->flags &= ~(SESS_RECONNECT|SESS_REDIRECT); } - - if((sess->soc = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - fprintf(stderr, "tcpConnect: socket: %m"); - return 0; +#endif + sess->reconnect_cnt++; } + snprintf(pbuf, sizeof(pbuf), "%d", op->port); memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_INET; + hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - - debug(3, "targetAddress=%s port=%d", op->targetAddress, op->port); - if(inet_aton(op->targetAddress, &ipn)) - hints.ai_flags |= AI_NUMERICHOST; - if((val = getaddrinfo(op->targetAddress, NULL, &hints, &res)) != 0) { + debug(1, "targetAddress=%s port=%d", op->targetAddress, op->port); + if((val = getaddrinfo(op->targetAddress, pbuf, &hints, &res0)) != 0) { fprintf(stderr, "getaddrinfo(%s): %s\n", op->targetAddress, gai_strerror(val)); return 0; } - memcpy(&sn, res->ai_addr, sizeof(struct sockaddr_in)); - sn.sin_port = htons(op->port); - freeaddrinfo(res); + sess->flags &= ~SESS_CONNECTED; + sv_errno = 0; + soc = -1; + for(res = res0; res; res = res->ai_next) { + soc = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (soc == -1) + continue; // from Patrick.Guelat@imp.ch: // iscontrol can be called without waiting for the socket entry to time out val = 1; - if(setsockopt(sess->soc, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(val)) < 0) { + if(setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, &val, (socklen_t)sizeof(val)) < 0) { fprintf(stderr, "Cannot set socket SO_REUSEADDR %d: %s\n\n", errno, strerror(errno)); } - sess->flags &= ~SESS_CONNECTED; + if(connect(soc, res->ai_addr, res->ai_addrlen) == 0) + break; + sv_errno = errno; + close(soc); + soc = -1; + } + freeaddrinfo(res0); + if(soc != -1) { + sess->soc = soc; - if(connect(sess->soc, (struct sockaddr *)&sn, sizeof(struct sockaddr_in)) != -1) { #if 0 struct timeval timeout; @@ -190,21 +196,29 @@ tcpConnect(isess_t *sess) } sess->flags |= SESS_CONNECTED; return T1; - } - sv_errno = errno; + fprintf(stderr, "errno=%d\n", sv_errno); perror("connect"); switch(sv_errno) { case ECONNREFUSED: case ENETUNREACH: case ETIMEDOUT: + if((sess->flags & SESS_REDIRECT) == 0) { + if(strcmp(op->targetAddress, sess->target.address) != 0) { + syslog(LOG_INFO, "reconnecting to original target address"); + free(op->targetAddress); + op->targetAddress = sess->target.address; + op->port = sess->target.port; + op->targetPortalGroupTag = sess->target.pgt; + return T1; + } + } sleep(5); // for now ... return T1; default: return 0; // terminal error } - } int @@ -416,7 +430,6 @@ supervise(isess_t *sess) } else { - if(ioctl(sess->fd, ISCSIRESTART)) { perror("ISCSIRESTART"); return -1; @@ -554,7 +567,10 @@ doLogin(isess_t *sess) return T7; case 2: // initiator terminal error + return 0; case 3: // target terminal error -- could retry ... + sleep(5); + return T7; // lets try default: return 0; } @@ -654,6 +670,9 @@ fsm(isc_opt_t *op) sess->op = op; sess->fd = -1; sess->soc = -1; + sess->target.address = strdup(op->targetAddress); + sess->target.port = op->port; + sess->target.pgt = op->targetPortalGroupTag; sess->flags = SESS_INITIALLOGIN | SESS_INITIALLOGIN1; diff --git a/sbin/iscontrol/iscontrol.8 b/sbin/iscontrol/iscontrol.8 index 4ae0d3f..aaa126d 100644 --- a/sbin/iscontrol/iscontrol.8 +++ b/sbin/iscontrol/iscontrol.8 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2007 Daniel Braniss +.\" Copyright (c) 2007-2008 Daniel Braniss .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without diff --git a/sbin/iscontrol/iscontrol.c b/sbin/iscontrol/iscontrol.c index d5d5929..8cfa5fa 100644 --- a/sbin/iscontrol/iscontrol.c +++ b/sbin/iscontrol/iscontrol.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,7 +55,6 @@ __FBSDID("$FreeBSD$"); #include "iscsi.h" #include "iscontrol.h" -//#include "pdu.h" #define USAGE "[-v] [-d] [-c config] [-n name] [-t target] " #define OPTIONS "vdc:t:n:" @@ -129,7 +128,7 @@ int main(int cc, char **vv) { int ch, disco; - char *pname, *p, *ta, *kw; + char *pname, *p, *q, *ta, *kw; isc_opt_t *op; FILE *fd; @@ -191,12 +190,18 @@ main(int cc, char **vv) fprintf(stderr, "No target!\n"); goto badu; } - if((p = strchr(op->targetAddress, ':')) != NULL) { + q = op->targetAddress; + if(*q == '[' && (q = strchr(q, ']')) != NULL) { + *q++ = '\0'; + op->targetAddress++; + } else + q = op->targetAddress; + if((p = strchr(q, ':')) != NULL) { *p++ = 0; op->port = atoi(p); p = strchr(p, ','); } - if(p || ((p = strchr(op->targetAddress, ',')) != NULL)) { + if(p || ((p = strchr(q, ',')) != NULL)) { *p++ = 0; op->targetPortalGroupTag = atoi(p); } diff --git a/sbin/iscontrol/iscontrol.h b/sbin/iscontrol/iscontrol.h index c93c35a..a89d7af 100644 --- a/sbin/iscontrol/iscontrol.h +++ b/sbin/iscontrol/iscontrol.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,6 +45,12 @@ int vflag; typedef int auth_t(void *sess); +typedef struct { + char *address; + int port; + int pgt; +} target_t; + typedef struct isess { int flags; #define SESS_CONNECTED BIT(0) @@ -61,6 +67,7 @@ typedef struct isess { isc_opt_t *op; // operational values + target_t target; // the Original target address int fd; // the session fd int soc; // the socket iscsi_cam_t cam; diff --git a/sbin/iscontrol/iscsi.conf.5 b/sbin/iscontrol/iscsi.conf.5 index 3388746..2edcd35 100644 --- a/sbin/iscontrol/iscsi.conf.5 +++ b/sbin/iscontrol/iscsi.conf.5 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2007 Daniel Braniss +.\" Copyright (c) 2007-2008 Daniel Braniss .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without diff --git a/sbin/iscontrol/login.c b/sbin/iscontrol/login.c index 44ea889..ec17f21 100644 --- a/sbin/iscontrol/login.c +++ b/sbin/iscontrol/login.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$"); #include "iscsi.h" #include "iscontrol.h" -#include "pdu.h" static char *status_class1[] = { "Initiator error", @@ -173,16 +172,18 @@ processParams(isess_t *sess, pdu_t *pp) klen = eq - ptr; if(klen > 0) { if(strncmp(ptr, "TargetAddress", klen) == 0) { - char *p, *q; + char *p, *q, *ta = NULL; // TargetAddress=domainname[:port][,portal-group-tag] // XXX: if(op->targetAddress) free(op->targetAddress); q = op->targetAddress = strdup(eq+1); if(*q == '[') { // bracketed IPv6 - if((q = strchr(q, ']')) != NULL) - q++; - else + if((q = strchr(q, ']')) != NULL) { + *q++ = '\0'; + ta = op->targetAddress; + op->targetAddress = strdup(ta+1); + } else q = op->targetAddress; } if((p = strchr(q, ',')) != NULL) { @@ -193,6 +194,8 @@ processParams(isess_t *sess, pdu_t *pp) *p++ = 0; op->port = atoi(p); } + if(ta) + free(ta); } else if(strncmp(ptr, "MaxRecvDataSegmentLength", klen) == 0) { // danny's RFC op->maxXmitDataSegmentLength = strtol(eq+1, (char **)NULL, 0); diff --git a/sbin/iscontrol/misc.c b/sbin/iscontrol/misc.c index 4ac3f0a..9634a1b 100644 --- a/sbin/iscontrol/misc.c +++ b/sbin/iscontrol/misc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/sbin/iscontrol/pdu.c b/sbin/iscontrol/pdu.c index 18dfdfc..980d20a 100644 --- a/sbin/iscontrol/pdu.c +++ b/sbin/iscontrol/pdu.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,7 +45,6 @@ __FBSDID("$FreeBSD$"); #include "iscsi.h" #include "iscontrol.h" -#include "pdu.h" int xmitpdu(isess_t *sess, pdu_t *pp) diff --git a/sys/dev/iscsi/initiator/isc_cam.c b/sys/dev/iscsi/initiator/isc_cam.c index d978db3..fbd5b3d 100644 --- a/sys/dev/iscsi/initiator/isc_cam.c +++ b/sys/dev/iscsi/initiator/isc_cam.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -193,6 +193,23 @@ _inq(struct cam_sim *sim, union ccb *ccb, int maxluns) cpi->ccb_h.status = CAM_REQ_CMP; } +static __inline int +_scsi_encap(struct cam_sim *sim, union ccb *ccb) +{ + int ret; + +#if __FreeBSD_version < 700000 + ret = scsi_encap(sim, ccb); +#else + struct isc_softc *isp = (struct isc_softc *)cam_sim_softc(sim); + + mtx_unlock(&isp->cam_mtx); + ret = scsi_encap(sim, ccb); + mtx_lock(&isp->cam_mtx); +#endif + return ret; +} + static void ic_action(struct cam_sim *sim, union ccb *ccb) { @@ -281,17 +298,8 @@ ic_action(struct cam_sim *sim, union ccb *ccb) ccb_h->status = CAM_LUN_INVALID; break; } -#if __FreeBSD_version < 700000 - if(scsi_encap(sim, ccb) != 0) + if(_scsi_encap(sim, ccb) != 0) return; -#else - mtx_unlock(&isp->cam_mtx); - if(scsi_encap(sim, ccb) != 0) { - mtx_lock(&isp->cam_mtx); - return; - } - mtx_lock(&isp->cam_mtx); -#endif break; } @@ -396,7 +404,11 @@ ic_init(struct isc_softc *isp) return ENXIO; } CAM_LOCK(isp); - if(xpt_bus_register(sim, NULL, 0/*bus_number*/) != CAM_SUCCESS) + if(xpt_bus_register(sim, +#if __FreeBSD_version >= 700000 + NULL, +#endif + 0/*bus_number*/) != CAM_SUCCESS) goto bad; if(xpt_create_path(&path, xpt_periph, cam_sim_path(sim), diff --git a/sys/dev/iscsi/initiator/isc_sm.c b/sys/dev/iscsi/initiator/isc_sm.c index f024aef..3f4f377 100644 --- a/sys/dev/iscsi/initiator/isc_sm.c +++ b/sys/dev/iscsi/initiator/isc_sm.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -174,7 +174,7 @@ _nop_out(isc_session_t *sp) /* | only send a nop if window is closed. */ - if((pq = pdu_alloc(sp->isc, 0)) == NULL) + if((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) // I guess we ran out of resources return; nop_out = &pq->pdu.ipdu.nop_out; @@ -224,7 +224,6 @@ _nop_in(isc_session_t *sp, pduq_t *pq) nop_out = &pp->ipdu.nop_out; nop_out->sn.maxcmd = 0; memset(nop_out->mbz, 0, sizeof(nop_out->mbz)); - (void)isc_qout(sp, pq); //XXX: should check return? return; } @@ -318,27 +317,24 @@ isc_qout(isc_session_t *sp, pduq_t *pq) i_nqueue_csnd(sp, pq); sdebug(5, "enqued: pq=%p", pq); -#ifdef ISC_OWAITING - if(sp->flags & ISC_OWAITING) { - mtx_lock(&sp->io_mtx); // XXX - wakeup(&sp->flags); - mtx_unlock(&sp->io_mtx); // XXX - } -#else + + mtx_lock(&sp->io_mtx); + sp->flags |= ISC_OQNOTEMPTY; + if(sp->flags & ISC_OWAITING) wakeup(&sp->flags); -#endif + mtx_unlock(&sp->io_mtx); + return error; } /* | called when a fullPhase is restarted */ -static int +static void ism_restart(isc_session_t *sp) { int lastcmd; sdebug(2, "restart ..."); - sp->flags |= ISC_SM_HOLD; lastcmd = iscsi_requeue(sp); #if 0 if(lastcmd != sp->sn.cmd) { @@ -346,8 +342,13 @@ ism_restart(isc_session_t *sp) sp->sn.cmd = lastcmd; } #endif - sp->flags &= ~ISC_SM_HOLD; - return 0; + mtx_lock(&sp->io_mtx); + if(sp->flags & ISC_OWAITING) { + wakeup(&sp->flags); + } + mtx_unlock(&sp->io_mtx); + + sdebug(2, "restarted lastcmd=0x%x", lastcmd); } int @@ -367,7 +368,7 @@ ism_fullfeature(struct cdev *dev, int flag) error = ic_fullfeature(dev); break; case 2: // restart - error = ism_restart(sp); + ism_restart(sp); break; } return error; @@ -454,32 +455,40 @@ ism_recv(isc_session_t *sp, pduq_t *pq) } } +/* + | go through the out queues looking for work + | if either nothing to do, or window is closed + | return. + */ static int proc_out(isc_session_t *sp) { sn_t *sn = &sp->sn; pduq_t *pq; - int error, ndone = 0; + int error, ndone; int which; debug_called(8); + error = ndone = 0; - while(1) { + while(sp->flags & ISC_LINK_UP) { pdu_t *pp; bhs_t *bhs; - /* | check if there is outstanding work in: - | 1- the Inmediate queue + | 1- the Immediate queue | 2- the R2T queue | 3- the cmd queue, only if the command window allows it. */ which = BIT(0) | BIT(1); - if(SNA_GT(sn->cmd, sn->maxCmd) == 0) + if(SNA_GT(sn->cmd, sn->maxCmd) == 0) // if(sn->maxCmd - sn->smc + 1) > 0 which |= BIT(2); + sdebug(4, "which=%d sn->maxCmd=%d sn->cmd=%d", which, sn->maxCmd, sn->cmd); + if((pq = i_dqueue_snd(sp, which)) == NULL) break; + sdebug(4, "pq=%p", pq); pp = &pq->pdu; bhs = &pp->ipdu.bhs; @@ -510,38 +519,45 @@ proc_out(isc_session_t *sp) // XXX: and now? } - sdebug(5, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", + sdebug(4, "opcode=0x%x sn(cmd=0x%x expCmd=0x%x maxCmd=0x%x expStat=0x%x itt=0x%x)", bhs->opcode, sn->cmd, sn->expCmd, sn->maxCmd, sn->expStat, sn->itt); if(pq->ccb) i_nqueue_hld(sp, pq); - if((error = isc_sendPDU(sp, pq)) == 0) + if((error = isc_sendPDU(sp, pq)) == 0) { ndone++; + if(pq->ccb == NULL) + pdu_free(sp->isc, pq); + } else { xdebug("error=%d ndone=%d opcode=0x%x ccb=%p itt=%x", error, ndone, bhs->opcode, pq->ccb, ntohl(bhs->itt)); - if(error == EPIPE) { - // XXX: better do some error recovery ... + if(pq->ccb) + i_remove_hld(sp, pq); + switch(error) { + case EPIPE: + sp->flags &= ~ISC_LINK_UP; + + case EAGAIN: + xdebug("requed"); + i_rqueue_pdu(sp, pq); break; - } -#if 0 + + default: if(pq->ccb) { - i_remove_hld(sp, pq); - pq->ccb->ccb_h.status |= CAM_UNREC_HBA_ERROR; // some better error? - XPT_DONE(pq->ccb); + xdebug("back to cam"); + pq->ccb->ccb_h.status |= CAM_REQUEUE_REQ; // some better error? + XPT_DONE(sp->isc, pq->ccb); + pdu_free(sp->isc, pq); } - else { - // XXX: now what? - // how do we pass back an error? + else + xdebug("we lost it!"); } -#endif } - if(pq->ccb == NULL || error) - pdu_free(sp->isc, pq); } - return ndone; + return error; } /* @@ -551,42 +567,46 @@ static void ism_proc(void *vp) { isc_session_t *sp = (isc_session_t *)vp; - int odone; + int error; debug_called(8); - sdebug(3, "started"); sp->flags |= ISC_SM_RUNNING; + sdebug(3, "started sp->flags=%x", sp->flags); do { - if(sp->flags & ISC_SM_HOLD) - odone = 0; - else - odone = proc_out(sp); - sdebug(7, "odone=%d", odone); - if(odone == 0) { + if((sp->flags & ISC_HOLD) == 0) { + error = proc_out(sp); + if(error) { + sdebug(3, "error=%d", error); + } + } mtx_lock(&sp->io_mtx); -#ifdef ISC_OWAITING + if((sp->flags & ISC_LINK_UP) == 0) { + wakeup(&sp->soc); + } + + if(!(sp->flags & ISC_OQNOTEMPTY)) { sp->flags |= ISC_OWAITING; -#endif - if((msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) - && (sp->flags & ISC_CON_RUNNING)) + if(msleep(&sp->flags, &sp->io_mtx, PRIBIO, "isc_proc", hz*30) == EWOULDBLOCK) { + if(sp->flags & ISC_CON_RUNNING) _nop_out(sp); -#ifdef ISC_OWAITING + } sp->flags &= ~ISC_OWAITING; -#endif - mtx_unlock(&sp->io_mtx); } + sp->flags &= ~ISC_OQNOTEMPTY; + mtx_unlock(&sp->io_mtx); } while(sp->flags & ISC_SM_RUN); sp->flags &= ~ISC_SM_RUNNING; + sdebug(3, "dropped ISC_SM_RUNNING"); #if __FreeBSD_version >= 700000 destroy_dev(sp->dev); #endif + wakeup(sp); - sdebug(3, "terminated"); + debug(3, "terminated sp=%p sp->sid=%d", sp, sp->sid); - wakeup(sp); kproc_exit(0); } @@ -695,6 +715,13 @@ isc_add_sysctls(isc_session_t *sp) CTLFLAG_RD, (void *)sp, 0, isc_dump_stats, "A", "statistics"); + + SYSCTL_ADD_INT(&sp->clist, + SYSCTL_CHILDREN(sp->oid), + OID_AUTO, + "douio", + CTLFLAG_RW, + &sp->douio, 0, "enable uio on read"); } void @@ -782,5 +809,6 @@ ism_start(isc_session_t *sp) sp->flags |= ISC_SM_RUN; + debug(4, "starting ism_proc: sp->sid=%d", sp->sid); return kproc_create(ism_proc, sp, &sp->stp, 0, 0, "ism_%d", sp->sid); } diff --git a/sys/dev/iscsi/initiator/isc_soc.c b/sys/dev/iscsi/initiator/isc_soc.c index bbe891e..0150ce7 100644 --- a/sys/dev/iscsi/initiator/isc_soc.c +++ b/sys/dev/iscsi/initiator/isc_soc.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,157 +55,179 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include + #include #include -#ifndef USE_MBUF +#ifndef NO_USE_MBUF #define USE_MBUF #endif #ifdef USE_MBUF + +static int ou_refcnt = 0; + /* - | a dummy function for freeing external storage for mbuf + | function for freeing external storage for mbuf */ static void -nil_fn(void *a, void *b) +ext_free(void *a, void *b) { + pduq_t *pq = b; + + if(pq->buf != NULL) { + debug(3, "ou_refcnt=%d a=%p b=%p", ou_refcnt, a, pq->buf); + free(pq->buf, M_ISCSI); + pq->buf = NULL; + } } -static int nil_refcnt = 0; -#endif /* USE_MBUF */ int isc_sendPDU(isc_session_t *sp, pduq_t *pq) { + struct mbuf *mh, **mp; pdu_t *pp = &pq->pdu; int len, error; -#ifdef USE_MBUF - struct mbuf *mh, **mp; -#else - struct uio *uio = &pq->uio; - struct iovec *iv; -#endif /* USE_MBUF */ debug_called(8); - -#ifndef USE_MBUF - bzero(uio, sizeof(struct uio)); - uio->uio_rw = UIO_WRITE; - uio->uio_segflg = UIO_SYSSPACE; - uio->uio_td = sp->td; - uio->uio_iov = iv = pq->iov; - - iv->iov_base = &pp->ipdu; - iv->iov_len = sizeof(union ipdu_u); - uio->uio_resid = pq->len; - iv++; -#else /* USE_MBUF */ - /* mbuf for the iSCSI header */ - MGETHDR(mh, M_WAIT, MT_DATA); + /* + | mbuf for the iSCSI header + */ + MGETHDR(mh, M_TRYWAIT, MT_DATA); mh->m_len = mh->m_pkthdr.len = sizeof(union ipdu_u); mh->m_pkthdr.rcvif = NULL; MH_ALIGN(mh, sizeof(union ipdu_u)); bcopy(&pp->ipdu, mh->m_data, sizeof(union ipdu_u)); mh->m_next = NULL; -#endif /* USE_MBUF */ if(sp->hdrDigest) pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0); if(pp->ahs_len) { -#ifndef USE_MBUF - iv->iov_base = pp->ahs; - iv->iov_len = pp->ahs_len; - iv++; -#else /* USE_MBUF */ - /* Add any AHS to the iSCSI hdr mbuf */ - /* XXX Assert: (mh->m_pkthdr.len + pp->ahs_len) < MHLEN */ + /* + | Add any AHS to the iSCSI hdr mbuf + | XXX Assert: (mh->m_pkthdr.len + pp->ahs_len) < MHLEN + */ bcopy(pp->ahs, (mh->m_data + mh->m_len), pp->ahs_len); mh->m_len += pp->ahs_len; mh->m_pkthdr.len += pp->ahs_len; -#endif /* USE_MBUF */ + if(sp->hdrDigest) pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig); } if(sp->hdrDigest) { debug(2, "hdr_dig=%x", pq->pdu.hdr_dig); -#ifndef USE_MBUF - iv->iov_base = &pp->hdr_dig; - iv->iov_len = sizeof(int); - iv++; -#else /* USE_MBUF */ - /* Add header digest to the iSCSI hdr mbuf */ - /* XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN */ + /* + | Add header digest to the iSCSI hdr mbuf + | XXX Assert: (mh->m_pkthdr.len + 4) < MHLEN + */ bcopy(&pp->hdr_dig, (mh->m_data + mh->m_len), sizeof(int)); mh->m_len += sizeof(int); mh->m_pkthdr.len += sizeof(int); -#endif /* USE_MBUF */ } -#ifdef USE_MBUF mp = &mh->m_next; -#endif /* USE_MBUF */ if(pq->pdu.ds) { -#ifndef USE_MBUF - iv->iov_base = pp->ds; - iv->iov_len = pp->ds_len; - while(iv->iov_len & 03) // the specs say it must be int alligned - iv->iov_len++; - iv++; -#else /* USE_MBUF */ struct mbuf *md; int off = 0; len = pp->ds_len; while(len & 03) // the specs say it must be int alligned len++; - - while (len > 0) { + while(len > 0) { int l; - MGET(md, M_WAIT, MT_DATA); - md->m_ext.ref_cnt = &nil_refcnt; + MGET(md, M_TRYWAIT, MT_DATA); + md->m_ext.ref_cnt = &ou_refcnt; l = min(MCLBYTES, len); - MEXTADD(md, pp->ds + off, l, nil_fn, - pp->ds + off, NULL, 0, EXT_EXTREF); + debug(5, "setting ext_free(arg=%p len/l=%d/%d)", pq->buf, len, l); + MEXTADD(md, pp->ds + off, l, ext_free, pp->ds + off, pq, 0, EXT_EXTREF); md->m_len = l; md->m_next = NULL; mh->m_pkthdr.len += l; *mp = md; mp = &md->m_next; - len -= l; off += l; } -#endif /* USE_MBUF */ } if(sp->dataDigest) { -#ifdef USE_MBUF struct mbuf *me; -#endif /* USE_MBUF */ pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0); -#ifndef USE_MBUF - iv->iov_base = &pp->ds_dig; - iv->iov_len = sizeof(int); - iv++; -#else /* USE_MBUF */ - MGET(me, M_WAIT, MT_DATA); + + MGET(me, M_TRYWAIT, MT_DATA); me->m_len = sizeof(int); MH_ALIGN(mh, sizeof(int)); bcopy(&pp->ds_dig, me->m_data, sizeof(int)); me->m_next = NULL; - mh->m_pkthdr.len += sizeof(int); *mp = me; -#endif /* USE_MBUF */ } + if((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) { + sdebug(3, "error=%d", error); + return error; + } + sp->stats.nsent++; + getbintime(&sp->stats.t_sent); + return 0; +} +#else /* NO_USE_MBUF */ +int +isc_sendPDU(isc_session_t *sp, pduq_t *pq) +{ + struct uio *uio = &pq->uio; + struct iovec *iv; + pdu_t *pp = &pq->pdu; + int len, error; + + debug_called(8); + + bzero(uio, sizeof(struct uio)); + uio->uio_rw = UIO_WRITE; + uio->uio_segflg = UIO_SYSSPACE; + uio->uio_td = sp->td; + uio->uio_iov = iv = pq->iov; + + iv->iov_base = &pp->ipdu; + iv->iov_len = sizeof(union ipdu_u); + uio->uio_resid = pq->len; + iv++; + if(sp->hdrDigest) + pq->pdu.hdr_dig = sp->hdrDigest(&pp->ipdu, sizeof(union ipdu_u), 0); + if(pp->ahs_len) { + iv->iov_base = pp->ahs; + iv->iov_len = pp->ahs_len; + iv++; -#ifndef USE_MBUF + if(sp->hdrDigest) + pq->pdu.hdr_dig = sp->hdrDigest(&pp->ahs, pp->ahs_len, pq->pdu.hdr_dig); + } + if(sp->hdrDigest) { + debug(2, "hdr_dig=%x", pq->pdu.hdr_dig); + iv->iov_base = &pp->hdr_dig; + iv->iov_len = sizeof(int); + iv++; + } + if(pq->pdu.ds) { + iv->iov_base = pp->ds; + iv->iov_len = pp->ds_len; + while(iv->iov_len & 03) // the specs say it must be int alligned + iv->iov_len++; + iv++; + } + if(sp->dataDigest) { + pp->ds_dig = sp->dataDigest(pp->ds, pp->ds_len, 0); + iv->iov_base = &pp->ds_dig; + iv->iov_len = sizeof(int); + iv++; + } uio->uio_iovcnt = iv - pq->iov; sdebug(5, "opcode=%x iovcnt=%d uio_resid=%d itt=%x", pp->ipdu.bhs.opcode, uio->uio_iovcnt, uio->uio_resid, ntohl(pp->ipdu.bhs.itt)); sdebug(5, "sp=%p sp->soc=%p uio=%p sp->td=%p", sp, sp->soc, uio, sp->td); - do { len = uio->uio_resid; error = sosend(sp->soc, NULL, uio, 0, 0, 0, sp->td); @@ -243,20 +265,12 @@ isc_sendPDU(isc_session_t *sp, pduq_t *pq) if(error == 0) { sp->stats.nsent++; getbintime(&sp->stats.t_sent); -#else /* USE_MBUF */ - if ((error = sosend(sp->soc, NULL, NULL, mh, 0, 0, sp->td)) != 0) { - m_freem(mh); - return (error); -#endif /* USE_MBUF */ + } -#ifndef USE_MBUF + return error; -#else /* USE_MBUF */ - sp->stats.nsent++; - getbintime(&sp->stats.t_sent); - return 0; -#endif /* USE_MBUF */ } +#endif /* USE_MBUF */ /* | wait till a PDU header is received @@ -312,10 +326,10 @@ so_getbhs(isc_session_t *sp) error, sp->soc->so_error, uio->uio_resid, iov->iov_len); if(!error && (uio->uio_resid > 0)) { + error = EPIPE; // was EAGAIN debug(2, "error=%d so_error=%d uio->uio_resid=%d iov.iov_len=%zd so_state=%x", error, sp->soc->so_error, uio->uio_resid, iov->iov_len, sp->soc->so_state); - error = EAGAIN; // EPIPE; } return error; @@ -379,7 +393,7 @@ so_recv(isc_session_t *sp, pduq_t *pq) len, sp->opt.targetAddress, sp->opt.targetName); #endif /* - | XXX: this will realy screwup the stream. + | XXX: this will really screwup the stream. | should clear up the buffer till a valid header | is found, or just close connection ... | should read the RFC. @@ -388,13 +402,55 @@ so_recv(isc_session_t *sp, pduq_t *pq) goto out; } if(len) { - int flags; + int flags = MSG_WAITALL; + struct mbuf **mp; + + mp = &pq->mp; uio->uio_resid = len; uio->uio_td = curthread; // why ... - flags = MSG_WAITALL; - - error = soreceive(so, NULL, uio, &pq->mp, NULL, &flags); + if(sp->douio) { + // it's more efficient to use mbufs -- why? + if(bhs->opcode == ISCSI_READ_DATA) { + pduq_t *opq; + + opq = i_search_hld(sp, pq->pdu.ipdu.bhs.itt, 1); + if(opq != NULL) { + union ccb *ccb = opq->ccb; + struct ccb_scsiio *csio = &ccb->csio; + pdu_t *opp = &opq->pdu; + scsi_req_t *cmd = &opp->ipdu.scsi_req; + data_in_t *rcmd = &pq->pdu.ipdu.data_in; + bhs_t *bhp = &opp->ipdu.bhs; + int r; + + if(bhp->opcode == ISCSI_SCSI_CMD + && cmd->R + && (ntohl(cmd->edtlen) >= pq->pdu.ds_len)) { + struct iovec *iov = pq->iov; + iov->iov_base = csio->data_ptr + ntohl(rcmd->bo); + iov->iov_len = pq->pdu.ds_len; + + uio->uio_rw = UIO_READ; + uio->uio_segflg = UIO_SYSSPACE; + uio->uio_iov = iov; + uio->uio_iovcnt = 1; + if(len > pq->pdu.ds_len) { + pq->iov[1].iov_base = &r; + pq->iov[1].iov_len = len - pq->pdu.ds_len; + uio->uio_iovcnt++; + } + mp = NULL; + + sdebug(4, "uio_resid=0x%x itt=0x%x bp=%p bo=%x len=%x/%x", + uio->uio_resid, + ntohl(pq->pdu.ipdu.bhs.itt), + csio->data_ptr, ntohl(rcmd->bo), ntohl(cmd->edtlen), pq->pdu.ds_len); + } + } + } + } + error = soreceive(so, NULL, uio, mp, NULL, &flags); //if(error == EAGAIN) // XXX: this needs work! it hangs iscontrol if(error || uio->uio_resid) @@ -432,6 +488,7 @@ so_recv(isc_session_t *sp, pduq_t *pq) error = EPIPE; return error; } + /* | wait for something to arrive. | and if the pdu is without errors, process it. @@ -451,7 +508,11 @@ so_input(isc_session_t *sp) /* | now read the rest. */ - pq = pdu_alloc(sp->isc, 1); // OK to WAIT + pq = pdu_alloc(sp->isc, M_NOWAIT); + if(pq == NULL) { // XXX: might cause a deadlock ... + debug(3, "out of pdus, wait"); + pq = pdu_alloc(sp->isc, M_NOWAIT); // OK to WAIT + } pq->pdu.ipdu.bhs = sp->bhs; pq->len = sizeof(bhs_t); // so far only the header was read error = so_recv(sp, pq); @@ -484,12 +545,11 @@ isc_soc(void *vp) debug_called(8); sp->flags |= ISC_CON_RUNNING; - if(sp->cam_path) ic_release(sp); error = 0; - while(sp->flags & ISC_CON_RUN) { + while((sp->flags & (ISC_CON_RUN | ISC_LINK_UP)) == (ISC_CON_RUN | ISC_LINK_UP)) { // XXX: hunting ... if(sp->soc == NULL || !(so->so_state & SS_ISCONNECTED)) { debug(2, "sp->soc=%p", sp->soc); @@ -497,27 +557,22 @@ isc_soc(void *vp) } error = so_input(sp); if(error == 0) { -#ifdef ISC_OWAITING mtx_lock(&sp->io_mtx); if(sp->flags & ISC_OWAITING) { - sp->flags &= ~ISC_OWAITING; - } wakeup(&sp->flags); + } mtx_unlock(&sp->io_mtx); -#else - wakeup(&sp->flags); -#endif - - } else if(error == EPIPE) + } else if(error == EPIPE) { break; + } else if(error == EAGAIN) { if(so->so_state & SS_ISCONNECTED) // there seems to be a problem in 6.0 ... tsleep(sp, PRIBIO, "isc_soc", 2*hz); } } - sdebug(2, "terminated, flags=%x so_count=%d so_state=%x error=%d", - sp->flags, so->so_count, so->so_state, error); + sdebug(2, "terminated, flags=%x so_count=%d so_state=%x error=%d proc=%p", + sp->flags, so->so_count, so->so_state, error, sp->proc); if((sp->proc != NULL) && sp->signal) { PROC_LOCK(sp->proc); psignal(sp->proc, sp->signal); @@ -534,36 +589,46 @@ isc_soc(void *vp) */ // do we need this mutex ...? mtx_lock(&sp->io_mtx); - sp->flags &= ~ISC_CON_RUNNING; + sp->flags &= ~(ISC_CON_RUNNING | ISC_LINK_UP); wakeup(&sp->soc); - mtx_unlock(&sp->io_mtx); + sdebug(2, "dropped ISC_CON_RUNNING"); + kproc_exit(0); } void isc_stop_receiver(isc_session_t *sp) { - int n = 5; + int n; + debug_called(8); + sdebug(3, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0); + mtx_lock(&sp->io_mtx); + sp->flags &= ~ISC_LINK_UP; + msleep(&sp->soc, &sp->io_mtx, PRIBIO|PDROP, "isc_stpc", 5*hz); - sdebug(4, "sp=%p sp->soc=%p", sp, sp? sp->soc: 0); soshutdown(sp->soc, SHUT_RD); mtx_lock(&sp->io_mtx); + sdebug(3, "soshutdown"); sp->flags &= ~ISC_CON_RUN; + n = 2; while(n-- && (sp->flags & ISC_CON_RUNNING)) { sdebug(3, "waiting n=%d... flags=%x", n, sp->flags); msleep(&sp->soc, &sp->io_mtx, PRIBIO, "isc_stpc", 5*hz); } mtx_unlock(&sp->io_mtx); + if(sp->fp != NULL) fdrop(sp->fp, sp->td); fputsock(sp->soc); sp->soc = NULL; sp->fp = NULL; + + sdebug(3, "done"); } void @@ -571,6 +636,7 @@ isc_start_receiver(isc_session_t *sp) { debug_called(8); - sp->flags |= ISC_CON_RUN; + sp->flags |= ISC_CON_RUN | ISC_LINK_UP; + kproc_create(isc_soc, sp, &sp->soc_proc, 0, 0, "iscsi%d", sp->sid); } diff --git a/sys/dev/iscsi/initiator/isc_subr.c b/sys/dev/iscsi/initiator/isc_subr.c index 333ee72..413a0b3 100644 --- a/sys/dev/iscsi/initiator/isc_subr.c +++ b/sys/dev/iscsi/initiator/isc_subr.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,8 +58,6 @@ __FBSDID("$FreeBSD$"); #include #include -MALLOC_DEFINE(M_PDU, "iSCSI pdu", "iSCSI driver"); - static char * i_strdupin(char *s, size_t maxlen) { diff --git a/sys/dev/iscsi/initiator/iscsi.c b/sys/dev/iscsi/initiator/iscsi.c index 1b0b00c..2296989 100644 --- a/sys/dev/iscsi/initiator/iscsi.c +++ b/sys/dev/iscsi/initiator/iscsi.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -60,7 +60,7 @@ __FBSDID("$FreeBSD$"); #include #include -static char *iscsi_driver_version = "2.0.99"; +static char *iscsi_driver_version = "2.1.0"; static struct isc_softc isc; @@ -296,6 +296,15 @@ iscsi_read(struct cdev *dev, struct uio *uio, int ioflag) sprintf(buf, "%03d] '%s' '%s'\n", i++, sp->opt.targetAddress, sp->opt.targetName); uiomove(buf, strlen(buf), uio); } + sprintf(buf, "%d/%d /---- free -----/\n", sc->npdu_alloc, sc->npdu_max); + i = 0; + uiomove(buf, strlen(buf), uio); + TAILQ_FOREACH(pq, &sc->freepdu, pq_link) { + if(uio->uio_resid == 0) + return 0; + sprintf(buf, "%03d] %06x\n", i++, ntohl(pq->pdu.ipdu.bhs.itt)); + uiomove(buf, strlen(buf), uio); + } } else { int i = 0; @@ -421,27 +430,37 @@ i_send(struct cdev *dev, caddr_t arg, struct thread *td) if(sp->soc == NULL) return ENOTCONN; - if((pq = pdu_alloc(sc, 0)) == NULL) + if((pq = pdu_alloc(sc, M_NOWAIT)) == NULL) return EAGAIN; pp = &pq->pdu; - pq->pdu = *(pdu_t *)arg; if((error = i_prepPDU(sp, pq)) != 0) - return error; + goto out; - sdebug(4, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len); - - pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSI, M_WAITOK); + sdebug(3, "len=%d ahs_len=%d ds_len=%d", pq->len, pp->ahs_len, pp->ds_len); + pq->buf = bp = malloc(pq->len - sizeof(union ipdu_u), M_ISCSI, M_NOWAIT); + if(pq->buf == NULL) { + error = EAGAIN; + goto out; + } if(pp->ahs_len) { n = pp->ahs_len; - copyin(pp->ahs, bp, n); + error = copyin(pp->ahs, bp, n); + if(error != 0) { + sdebug(3, "copyin ahs: error=%d", error); + goto out; + } pp->ahs = (ahs_t *)bp; bp += n; } if(pp->ds_len) { n = pp->ds_len; - copyin(pp->ds, bp, n); // can fail ... + error = copyin(pp->ds, bp, n); + if(error != 0) { + sdebug(3, "copyin ds: error=%d", error); + goto out; + } pp->ds = bp; bp += n; while(n & 03) { @@ -451,6 +470,13 @@ i_send(struct cdev *dev, caddr_t arg, struct thread *td) } error = isc_qout(sp, pq); +#if 1 + if(error == 0) + wakeup(&sp->flags); // XXX: to 'push' proc_out ... +#endif +out: + if(error) + pdu_free(sc, pq); return error; } @@ -475,6 +501,7 @@ i_recv(struct cdev *dev, caddr_t arg, struct thread *td) if(sp->soc == NULL) return ENOTCONN; + sdebug(3, ""); cnt = 6; // XXX: maybe the user can request a time out? mtx_lock(&sp->rsp_mtx); while((pq = TAILQ_FIRST(&sp->rsp)) == NULL) { @@ -487,7 +514,7 @@ i_recv(struct cdev *dev, caddr_t arg, struct thread *td) } mtx_unlock(&sp->rsp_mtx); - sdebug(3, "cnt=%d", cnt); + sdebug(4, "cnt=%d", cnt); if(pq == NULL) { error = ENOTCONN; @@ -600,11 +627,9 @@ i_create_session(struct cdev *dev, int *ndev) sp->opt.maxBurstLength = 65536; // 64k - sdebug(2, "sessionID=%d", n); + sdebug(2, "sessionID=%d sp=%p", n, sp); error = ism_start(sp); - sdebug(2, "error=%d", error); - return error; } @@ -648,7 +673,7 @@ iscsi_shutdown(void *v) return; } if(sc->eh == NULL) - debug(2, "sc->eh is NULL!"); + debug(2, "sc->eh is NULL"); else { EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->eh); debug(2, "done n=%d", sc->nsess); @@ -658,6 +683,42 @@ iscsi_shutdown(void *v) debug(2, "%2d] sp->flags=0x%08x", n, sp->flags); n++; } + debug(2, "done"); +} + +static int +init_pdus(struct isc_softc *sc) +{ + debug_called(8); + + sc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t), + NULL, NULL, NULL, NULL, + 0, 0); + if(sc->pdu_zone == NULL) { + printf("iscsi_initiator: uma_zcreate failed"); + return -1; + } + uma_zone_set_max(sc->pdu_zone, MAX_PDUS); + TAILQ_INIT(&sc->freepdu); + + return 0; +} + +static void +free_pdus(struct isc_softc *sc) +{ + pduq_t *pq; + + debug_called(8); + + if(sc->pdu_zone != NULL) { + TAILQ_FOREACH(pq, &sc->freepdu, pq_link) { + TAILQ_REMOVE(&sc->freepdu, pq, pq_link); + uma_zfree(sc->pdu_zone, pq); + } + uma_zdestroy(sc->pdu_zone); + sc->pdu_zone = NULL; + } } static void @@ -673,15 +734,9 @@ iscsi_start(void) sc->dev->si_drv1 = sc; TAILQ_INIT(&sc->isc_sess); + if(init_pdus(sc) != 0) + xdebug("pdu zone init failed!"); // XXX: should cause terminal failure ... - sc->pdu_zone = uma_zcreate("pdu", sizeof(pduq_t), - NULL, NULL, NULL, NULL, - 0, 0); - if(sc->pdu_zone == NULL) { - printf("iscsi_initiator: uma_zcreate failed"); - // XXX: and now what? - } - uma_zone_set_max(sc->pdu_zone, MAX_PDUS*2+1); mtx_init(&sc->mtx, "iscsi", NULL, MTX_DEF); mtx_init(&sc->pdu_mtx, "iscsi pdu pool", NULL, MTX_DEF); @@ -693,9 +748,12 @@ iscsi_start(void) #else sc->cam_sim = NULL; #endif + +#ifdef DO_EVENTHANDLER if((sc->eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, iscsi_shutdown, sc, SHUTDOWN_PRI_DEFAULT-1)) == NULL) xdebug("shutdown event registration failed\n"); +#endif /* | sysctl stuff */ @@ -734,6 +792,8 @@ iscsi_start(void) &sc->nsess, sizeof(sc->nsess), "number of active session"); + + printf("iscsi: version %s\n", iscsi_driver_version); } /* @@ -762,13 +822,15 @@ iscsi_stop(void) mtx_destroy(&sc->mtx); mtx_destroy(&sc->pdu_mtx); - uma_zdestroy(sc->pdu_zone); + free_pdus(sc); if(sc->dev) destroy_dev(sc->dev); if(sysctl_ctx_free(&sc->clist)) xdebug("sysctl_ctx_free failed"); + + iscsi_shutdown(sc); // XXX: check EVENTHANDLER_ ... } static int @@ -801,11 +863,27 @@ iscsi_modevent(module_t mod, int what, void *arg) } return 0; } + moduledata_t iscsi_mod = { "iscsi", (modeventhand_t) iscsi_modevent, 0 }; +#ifdef ISCSI_ROOT +static void +iscsi_rootconf(void) +{ +#if 0 + nfs_setup_diskless(); + if (nfs_diskless_valid) + rootdevnames[0] = "nfs:"; +#endif + printf("** iscsi_rootconf **\n"); +} + +SYSINIT(cpu_rootconf1, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, iscsi_rootconf, NULL) +#endif + DECLARE_MODULE(iscsi, iscsi_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE); MODULE_DEPEND(iscsi, cam, 1, 1, 1); diff --git a/sys/dev/iscsi/initiator/iscsi.h b/sys/dev/iscsi/initiator/iscsi.h index cbd9f22..2eace68 100644 --- a/sys/dev/iscsi/initiator/iscsi.h +++ b/sys/dev/iscsi/initiator/iscsi.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -294,6 +294,103 @@ typedef struct async { } async_t; +typedef struct login_req { + char cmd; // 0x03 + + u_char NSG:2; + u_char CSG:2; + u_char _:2; + u_char C:1; + u_char T:1; + + char v_max; + char v_min; + + int len; // remapped via standard bhs + char isid[6]; + short tsih; + int itt; // Initiator Task Tag; + + int CID:16; + int rsv:16; + + int cmdSN; + int expStatSN; + int unused[4]; +} login_req_t; + +typedef struct login_rsp { + char cmd; // 0x23 + u_char NSG:2; + u_char CSG:2; + u_char _1:2; + u_char C:1; + u_char T:1; + + char v_max; + char v_act; + + int len; // remapped via standard bhs + char isid[6]; + short tsih; + int itt; // Initiator Task Tag; + int _2; + rsp_sn_t sn; + int status:16; + int _3:16; + int _4[2]; +} login_rsp_t; + +typedef struct text_req { + char cmd; // 0x04 + + u_char _1:6; + u_char C:1; // Continuation + u_char F:1; // Final + char _2[2]; + + int len; + int itt; // Initiator Task Tag + int LUN[2]; + int ttt; // Target Transfer Tag + int cmdSN; + int expStatSN; + int unused[4]; +} text_req_t; + +typedef struct logout_req { + char cmd; // 0x06 + char reason; // 0 - close session + // 1 - close connection + // 2 - remove the connection for recovery + char _2[2]; + + int len; + int _r[2]; + int itt; // Initiator Task Tag; + + u_int CID:16; + u_int rsv:16; + + int cmdSN; + int expStatSN; + int unused[4]; +} logout_req_t; + +typedef struct logout_rsp { + char cmd; // 0x26 + char cbits; + char _1[2]; + int len; + int _2[2]; + int itt; + int _3; + rsp_sn_t sn; + short time2wait; + short time2retain; + int _4; +} logout_rsp_t; + union ipdu_u { bhs_t bhs; scsi_req_t scsi_req; diff --git a/sys/dev/iscsi/initiator/iscsi_subr.c b/sys/dev/iscsi/initiator/iscsi_subr.c index 6abe1f6..9ef92d5 100644 --- a/sys/dev/iscsi/initiator/iscsi_subr.c +++ b/sys/dev/iscsi/initiator/iscsi_subr.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -93,11 +93,20 @@ iscsi_r2t(isc_session_t *sp, pduq_t *opq, pduq_t *pq) sdebug(4, "edtl=%x ddtl=%x bo=%x dsn=%x bs=%x maxX=%x", edtl, ddtl, bo, dsn, bs, sp->opt.maxXmitDataSegmentLength); while(bleft > 0) { - wpq = pdu_alloc(sp->isc, 1); + wpq = pdu_alloc(sp->isc, M_NOWAIT); // testing ... if(wpq == NULL) { - // should not happen if above is 1 - sdebug(1, "now what?"); - return; + sdebug(3, "itt=%x r2tSN=%d bo=%x ddtl=%x W=%d", ntohl(r2t->itt), + ntohl(r2t->r2tSN), ntohl(r2t->bo), ntohl(r2t->ddtl), opp->ipdu.scsi_req.W); + sdebug(1, "npdu_max=%d npdu_alloc=%d", sp->isc->npdu_max, sp->isc->npdu_alloc); + + while((wpq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) { + sdebug(2, "waiting..."); +#if __FreeBSD_version >= 700000 + pause("isc_r2t", 5*hz); +#else + tsleep(sp->isc, 0, "isc_r2t", 5*hz); +#endif + } } cmd = &wpq->pdu.ipdu.data_out; cmd->opcode = ISCSI_WRITE_DATA; @@ -220,7 +229,7 @@ _scsi_done(struct isc_softc *isp, u_int response, u_int status, union ccb *ccb, //case 0x22: // Command Terminated //case 0x30: // ACA Active //case 0x40: // Task Aborted - ccb_h->status = CAM_REQ_ABORTED; + ccb_h->status = CAM_REQ_CMP_ERR; //CAM_REQ_ABORTED; } break; @@ -249,6 +258,7 @@ iscsi_requeue(isc_session_t *sp) debug_called(8); last = -1; i = 0; + sp->flags |= ISC_HOLD; while((pq = i_dqueue_hld(sp)) != NULL) { i++; _scsi_done(sp->isc, 0, 0x28, pq->ccb, NULL); @@ -258,6 +268,7 @@ iscsi_requeue(isc_session_t *sp) sdebug(2, "last=%x n=%x", last, n); pdu_free(sp->isc, pq); } + sp->flags &= ~ISC_HOLD; return i? last: sp->sn.cmd; } @@ -284,6 +295,10 @@ i_pdu_flush(isc_session_t *sp) pdu_free(sp->isc, pq); n++; } + while((pq = i_dqueue_wsnd(sp)) != NULL) { + pdu_free(sp->isc, pq); + n++; + } if(n != 0) xdebug("%d pdus recovered, should have been ZERO!", n); return n; @@ -329,6 +344,14 @@ iscsi_done(isc_session_t *sp, pduq_t *opq, pduq_t *pq) } // see RFC 3720, 10.9.1 page 146 +/* + | NOTE: + | the call to isc_stop_receiver is a kludge, + | instead, it should be handled by the userland controller, + | but that means that there should be a better way, other than + | sending a signal. Somehow, this packet should be supplied to + | the userland via read. + */ void iscsi_async(isc_session_t *sp, pduq_t *pq) { @@ -341,17 +364,22 @@ iscsi_async(isc_session_t *sp, pduq_t *pq) switch(cmd->asyncEvent) { case 0: // check status ... break; + case 1: // target request logout + isc_stop_receiver(sp); // XXX: temporary solution break; + case 2: // target indicates it wants to drop connection + isc_stop_receiver(sp); // XXX: temporary solution break; case 3: // target indicates it will drop all connections. - isc_stop_receiver(sp); + isc_stop_receiver(sp); // XXX: temporary solution break; case 4: // target request parameter negotiation break; + default: break; } @@ -430,12 +458,26 @@ scsi_encap(struct cam_sim *sim, union ccb *ccb) debug(4, "ccb->sp=%p", ccb_h->spriv_ptr0); sp = ccb_h->spriv_ptr0; - if((pq = pdu_alloc(isp, 1)) == NULL) { // cannot happen + if((pq = pdu_alloc(isp, M_NOWAIT)) == NULL) { + debug(2, "ccb->sp=%p", ccb_h->spriv_ptr0); + sdebug(1, "pdu_alloc failed sc->npdu_max=%d npdu_alloc=%d", + sp->isc->npdu_max, sp->isc->npdu_alloc); + while((pq = pdu_alloc(sp->isc, M_NOWAIT)) == NULL) { + sdebug(3, "waiting..."); +#if __FreeBSD_version >= 700000 + pause("isc_encap", 5*hz); +#else + tsleep(sp->isc, 0, "isc_encap", 5*hz); +#endif + } +#if 0 sdebug(3, "freezing"); ccb->ccb_h.status = CAM_REQUEUE_REQ; ic_freeze(sp); return 0; +#endif } + #if 0 if((sp->flags & ISC_FFPHASE) == 0) { ccb->ccb_h.status = CAM_DEV_NOT_THERE; // CAM_NO_NEXUS; @@ -523,21 +565,24 @@ scsi_decap(isc_session_t *sp, pduq_t *opq, pduq_t *pq) switch(pq->pdu.ipdu.bhs.opcode) { case ISCSI_READ_DATA: // SCSI Data in { - caddr_t bp = mtod(pq->mp, caddr_t); + caddr_t bp = NULL; // = mtod(pq->mp, caddr_t); data_in_t *rcmd = &pq->pdu.ipdu.data_in; if(cmd->R) { - sdebug(5, "copy to=%p from=%p l1=%d l2=%d", - csio->data_ptr, bp, - ntohl(cmd->edtlen), pq->pdu.ds_len); + sdebug(5, "copy to=%p from=%p l1=%d l2=%d mp@%p", + csio->data_ptr, bp? mtod(pq->mp, caddr_t): 0, + ntohl(cmd->edtlen), pq->pdu.ds_len, pq->mp); if(ntohl(cmd->edtlen) >= pq->pdu.ds_len) { int offset, len = pq->pdu.ds_len; + + if(pq->mp != NULL) { caddr_t dp; offset = ntohl(rcmd->bo); dp = csio->data_ptr + offset; i_mbufcopy(pq->mp, dp, len); } + } else { xdebug("edtlen=%d < ds_len=%d", ntohl(cmd->edtlen), pq->pdu.ds_len); diff --git a/sys/dev/iscsi/initiator/iscsivar.h b/sys/dev/iscsi/initiator/iscsivar.h index fa54b19..128a745 100644 --- a/sys/dev/iscsi/initiator/iscsivar.h +++ b/sys/dev/iscsi/initiator/iscsivar.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005-2007 Daniel Braniss + * Copyright (c) 2005-2008 Daniel Braniss * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,7 +46,7 @@ extern int iscsi_debug; #define sdebug(level, fmt, args...) #endif /* ISCSI_INITIATOR_DEBUG */ -#define xdebug(fmt, args...) printf("%s: " fmt "\n", __func__ , ##args) +#define xdebug(fmt, args...) printf(">>> %s: " fmt "\n", __func__ , ##args) #define MAX_SESSIONS ISCSI_MAX_TARGETS @@ -61,13 +61,13 @@ MALLOC_DECLARE(M_PDU); #define ISC_SM_RUN BIT(0) #define ISC_SM_RUNNING BIT(1) -#define ISC_SM_HOLD BIT(2) +#define ISC_LINK_UP BIT(2) #define ISC_CON_RUN BIT(3) #define ISC_CON_RUNNING BIT(4) #define ISC_KILL BIT(5) -#define ISC_IWAITING BIT(6) -//#define ISC_OWAITING BIT(7) +#define ISC_OQNOTEMPTY BIT(6) +#define ISC_OWAITING BIT(7) #define ISC_FFPHASE BIT(8) #define ISC_FFPWAIT BIT(9) @@ -76,6 +76,9 @@ MALLOC_DECLARE(M_PDU); #define ISC_FROZEN BIT(12) #define ISC_STALLED BIT(13) +#define ISC_HOLD BIT(14) +#define ISC_HOLDED BIT(15) + #define ISC_SHUTDOWN BIT(31) /* @@ -100,6 +103,9 @@ struct i_stats { /* | one per 'session' */ + +typedef TAILQ_HEAD(, pduq) queue_t; + typedef struct isc_session { TAILQ_ENTRY(isc_session) sp_link; int flags; @@ -137,13 +143,13 @@ typedef struct isc_session { struct mtx snd_mtx; struct mtx hld_mtx; struct mtx io_mtx; + queue_t rsp; + queue_t rsv; + queue_t csnd; + queue_t isnd; + queue_t wsnd; + queue_t hld; - TAILQ_HEAD(,pduq) rsp; - TAILQ_HEAD(,pduq) rsv; - TAILQ_HEAD(,pduq) csnd; - TAILQ_HEAD(,pduq) isnd; - TAILQ_HEAD(,pduq) wsnd; - TAILQ_HEAD(,pduq) hld; /* | negotiable values */ @@ -159,6 +165,7 @@ typedef struct isc_session { */ struct sysctl_ctx_list clist; struct sysctl_oid *oid; + int douio; //XXX: turn on/off uio on read } isc_session_t; typedef struct pduq { @@ -173,6 +180,7 @@ typedef struct pduq { struct iovec iov[5]; // XXX: careful ... struct mbuf *mp; struct bintime ts; + queue_t *pduq; } pduq_t; struct isc_softc { @@ -190,8 +198,9 @@ struct isc_softc { #ifdef ISCSI_INITIATOR_DEBUG int npdu_alloc, npdu_max; // for instrumentation #endif -#define MAX_PDUS 256 // XXX: at the moment this is arbitrary +#define MAX_PDUS (MAX_SESSIONS*256) // XXX: at the moment this is arbitrary uma_zone_t pdu_zone; // pool of free pdu's + TAILQ_HEAD(,pduq) freepdu; /* | cam stuff */ @@ -291,11 +300,17 @@ pdu_alloc(struct isc_softc *isc, int wait) { pduq_t *pq; - pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait? M_WAITOK: M_NOWAIT); - if(pq == NULL) { - // will not happend if M_WAITOK ... + mtx_lock(&isc->pdu_mtx); + if((pq = TAILQ_FIRST(&isc->freepdu)) == NULL) { + mtx_unlock(&isc->pdu_mtx); + pq = (pduq_t *)uma_zalloc(isc->pdu_zone, wait /* M_WAITOK or M_NOWAIT*/); + } + else { + TAILQ_REMOVE(&isc->freepdu, pq, pq_link); mtx_unlock(&isc->pdu_mtx); - debug(1, "out of mem"); + } + if(pq == NULL) { + debug(7, "out of mem"); return NULL; } #ifdef ISCSI_INITIATOR_DEBUG @@ -315,10 +330,12 @@ pdu_free(struct isc_softc *isc, pduq_t *pq) { if(pq->mp) m_freem(pq->mp); +#ifdef NO_USE_MBUF if(pq->buf != NULL) free(pq->buf, M_ISCSI); +#endif mtx_lock(&isc->pdu_mtx); - uma_zfree(isc->pdu_zone, pq); + TAILQ_INSERT_TAIL(&isc->freepdu, pq, pq_link); #ifdef ISCSI_INITIATOR_DEBUG isc->npdu_alloc--; #endif @@ -460,20 +477,32 @@ i_dqueue_snd(isc_session_t *sp, int which) if((which & BIT(0)) && (pq = TAILQ_FIRST(&sp->isnd)) != NULL) { sp->stats.nisnd--; TAILQ_REMOVE(&sp->isnd, pq, pq_link); + pq->pduq = &sp->isnd; // remember where you came from } else if((which & BIT(1)) && (pq = TAILQ_FIRST(&sp->wsnd)) != NULL) { sp->stats.nwsnd--; TAILQ_REMOVE(&sp->wsnd, pq, pq_link); + pq->pduq = &sp->wsnd; // remember where you came from } else if((which & BIT(2)) && (pq = TAILQ_FIRST(&sp->csnd)) != NULL) { sp->stats.ncsnd--; TAILQ_REMOVE(&sp->csnd, pq, pq_link); + pq->pduq = &sp->csnd; // remember where you came from } mtx_unlock(&sp->snd_mtx); return pq; } +static __inline void +i_rqueue_pdu(isc_session_t *sp, pduq_t *pq) +{ + mtx_lock(&sp->snd_mtx); + KASSERT(pq->pduq != NULL, ("pq->pduq is NULL")); + TAILQ_INSERT_TAIL(pq->pduq, pq, pq_link); + mtx_unlock(&sp->snd_mtx); +} + /* | Waiting for ACK (or something :-) */ -- cgit v1.1