Beispiel #1
0
static void _handle_ack(struct cxl_afu_h *afu)
{
	uint8_t data[sizeof(uint64_t)];

	if (!afu)
		fatal_msg("NULL afu passed to libcxl.c:_handle_ack");
	DPRINTF("MMIO ACK\n");
	if ((afu->mmio.type == PSLSE_MMIO_READ64)| (afu->mmio.type == PSLSE_MMIO_EBREAD)) {
		if (get_bytes_silent(afu->fd, sizeof(uint64_t), data, 1000, 0) <
		    0) {
			warn_msg("Socket failure getting MMIO Ack");
			_all_idle(afu);
			afu->mmio.data = 0xFEEDB00FFEEDB00FL;
		} else {
			memcpy(&(afu->mmio.data), data, sizeof(uint64_t));
			afu->mmio.data = ntohll(afu->mmio.data);
		}
	}
	if (afu->mmio.type == PSLSE_MMIO_READ32) {
		if (get_bytes_silent(afu->fd, sizeof(uint32_t), data, 1000, 0) <
		    0) {
			warn_msg("Socket failure getting MMIO Read 32 data");
			afu->mmio.data = 0xFEEDB00FL;
			_all_idle(afu);
		} else {
			memcpy(&(afu->mmio.data), data, sizeof(uint32_t));
			debug_msg("KEM:0x%08x", afu->mmio.data);
			afu->mmio.data = ntohl(afu->mmio.data);
			debug_msg("KEM:0x%08x", afu->mmio.data);
		}
	}
	afu->mmio.state = LIBCXL_REQ_IDLE;
}
Beispiel #2
0
// Attach to AFU
static void _attach(struct psl *psl, struct client *client)
{
	uint64_t wed;
	uint8_t ack;
	uint8_t buffer[MAX_LINE_CHARS];
	size_t size;

	// FIXME: This only works for dedicate mode

	// Get wed value from application
	ack = PSLSE_DETACH;
	size = sizeof(uint64_t);
	if (get_bytes_silent(client->fd, size, buffer, psl->timeout,
			     &(client->abort)) < 0) {
		warn_msg("Failed to get WED value from client");
		client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE);
		goto attach_done;
	}
	memcpy((char *)&wed, (char *)buffer, sizeof(uint64_t));
	wed = ntohll(wed);

	// Send start to AFU
	if (add_job(psl->job, PSL_JOB_START, wed) != NULL) {
		psl->idle_cycles = PSL_IDLE_CYCLES;
		ack = PSLSE_ATTACH;
	}

 attach_done:
	if (put_bytes(client->fd, 1, &ack, psl->dbg_fp, psl->dbg_id,
		      client->context) < 0) {
		client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE);
	}
}
Beispiel #3
0
// Handshake with client and attach to PSL
static struct client *_client_connect(int *fd, char *ip)
{
    struct client *client;
    uint8_t buffer[MAX_LINE_CHARS];
    uint8_t ack[3];
    uint16_t map;
    int rc;

    // Parse client handshake data
    ack[0] = PSLSE_DETACH;
    memset(buffer, '\0', MAX_LINE_CHARS);
    rc = get_bytes(*fd, 5, buffer, timeout, 0, fp, -1, -1);
    if ((rc < 0) || (strcmp((char *)buffer, "PSLSE"))) {
        info_msg("Connecting application is not PSLSE client\n");
        info_msg("Expected: \"PSLSE\" Got: \"%s\"", buffer);
        put_bytes(*fd, 1, ack, fp, -1, -1);
        close_socket(fd);
        return NULL;
    }
    rc = get_bytes_silent(*fd, 2, buffer, timeout, 0);
    if ((rc < 0) || ((uint8_t) buffer[0] != PSLSE_VERSION_MAJOR) ||
            ((uint8_t) buffer[1] != PSLSE_VERSION_MINOR)) {
        info_msg("Client is wrong version\n");
        put_bytes(*fd, 1, ack, fp, -1, -1);
        close_socket(fd);
        return NULL;
    }
    // Initialize client struct
    client = (struct client *)calloc(1, sizeof(struct client));
    client->fd = *fd;
    client->ip = ip;
    client->pending = 1;
    client->timeout = timeout;
    client->flushing = FLUSH_NONE;
    client->state = CLIENT_INIT;

    // Return acknowledge to client
    ack[0] = PSLSE_CONNECT;
    map = htons(afu_map);
    memcpy(&(ack[1]), &map, sizeof(map));
    if (put_bytes(client->fd, 3, ack, fp, -1, -1) < 0) {
        _free_client(client);
        return NULL;
    }

    info_msg("%s connected", client->ip);
    return client;
}
Beispiel #4
0
static int _handle_afu_error(struct cxl_afu_h *afu)
{
	uint64_t error;
	uint16_t size;
	uint8_t data[sizeof(error)];
	int i;

	if (!afu)
		fatal_msg("NULL afu passed to libcxl.c:_handle_afu_error");
	DPRINTF("AFU ERROR\n");
	if (get_bytes_silent(afu->fd, sizeof(error), data, 1000, 0) < 0) {
		warn_msg("Socket failure getting AFU ERROR");
		_all_idle(afu);
		return -1;
	}
	memcpy(&error, data, sizeof(error));
	error = ntohll(error);

	// Only track a single AFU error at a time
	pthread_mutex_lock(&(afu->event_lock));
	i = 0;
	while (afu->events[i] != NULL) {
		if (afu->events[i]->header.type == CXL_EVENT_AFU_ERROR) {
			pthread_mutex_unlock(&(afu->event_lock));
			return 0;
		}
		++i;
	}
	assert(i < EVENT_QUEUE_MAX);

	size = sizeof(struct cxl_event_header) +
	    sizeof(struct cxl_event_afu_error);
	afu->events[i] = (struct cxl_event *)calloc(1, size);
	afu->events[i]->header.type = CXL_EVENT_AFU_ERROR;
	afu->events[i]->header.size = size;
	afu->events[i]->header.process_element = afu->context;
	afu->events[i]->afu_error.error = error;

	do {
		i = write(afu->pipe[1], &(afu->events[i]->header.type), 1);
	}
	while ((i == 0) || (errno == EINTR));
	pthread_mutex_unlock(&(afu->event_lock));
	return i;
}
Beispiel #5
0
// Handle data returning from client for memory read
static void _handle_mem_read(struct cmd *cmd, struct cmd_event *event, int fd)
{
	uint8_t data[MAX_LINE_CHARS];
	uint64_t offset = event->addr & ~CACHELINE_MASK;

	// Client is returning data from memory read
	if (get_bytes_silent(fd, event->size, data, cmd->parms->timeout,
			     event->abort) < 0) {
		event->resp = PSL_RESPONSE_DERROR;
		event->state = MEM_DONE;
		debug_cmd_update(cmd->dbg_fp, cmd->dbg_id, event->tag,
				 event->context, event->resp);
		return;
	}
	memcpy((void *)&(event->data[offset]), (void *)&data, event->size);
	generate_cl_parity(event->data, event->parity);
	event->state = MEM_RECEIVED;
}
Beispiel #6
0
static int _handle_interrupt(struct cxl_afu_h *afu)
{
	uint16_t size, irq;
	uint8_t data[sizeof(irq)];
	int i;

	if (!afu)
		fatal_msg("NULL afu passed to libcxl.c:_handle_interrupt");
	DPRINTF("AFU INTERRUPT\n");
	if (get_bytes_silent(afu->fd, sizeof(irq), data, 1000, 0) < 0) {
		warn_msg("Socket failure getting IRQ");
		_all_idle(afu);
		return -1;
	}
	memcpy(&irq, data, sizeof(irq));
	irq = ntohs(irq);

	// Only track a single interrupt at a time
	pthread_mutex_lock(&(afu->event_lock));
	i = 0;
	while (afu->events[i] != NULL) {
		if (afu->events[i]->header.type == CXL_EVENT_AFU_INTERRUPT) {
			pthread_mutex_unlock(&(afu->event_lock));
			return 0;
		}
		++i;
	}
	assert(i < EVENT_QUEUE_MAX);

	size = sizeof(struct cxl_event_header) +
	    sizeof(struct cxl_event_afu_interrupt);
	afu->events[i] = (struct cxl_event *)calloc(1, size);
	afu->events[i]->header.type = CXL_EVENT_AFU_INTERRUPT;
	afu->events[i]->header.size = size;
	afu->events[i]->header.process_element = afu->context;
	afu->events[i]->irq.irq = irq;

	do {
		i = write(afu->pipe[1], &(afu->events[i]->header.type), 1);
	}
	while ((i == 0) || (errno == EINTR));
	pthread_mutex_unlock(&(afu->event_lock));
	return i;
}
Beispiel #7
0
static void *_client_loop(void *ptr)
{
    struct client *client = (struct client *)ptr;
    uint8_t data[2];
    int rc;

    pthread_mutex_lock(&lock);
    while (client->pending) {
        rc = bytes_ready(client->fd, client->timeout, &(client->abort));
        if (rc == 0) {
            lock_delay(&lock);
            continue;
        }
        if ((rc < 0) || get_bytes(client->fd, 1, data, 10,
                                  &(client->abort), fp, -1, -1) < 0) {
            client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE);
            break;
        }
        if (data[0] == PSLSE_QUERY) {
            if (get_bytes_silent(client->fd, 1, data, timeout,
                                 &(client->abort)) < 0) {
                debug_msg("_client_loop failed PSLSE_QUERY");
                client_drop(client, PSL_IDLE_CYCLES,
                            CLIENT_NONE);
                break;
            }
            _query(client, data[0]);
            lock_delay(&lock);
            continue;
        }
        if (data[0] == PSLSE_MAX_INT) {
            if (get_bytes(client->fd, 2, data, timeout,
                          &(client->abort), fp, -1, -1) < 0) {
                client_drop(client, PSL_IDLE_CYCLES,
                            CLIENT_NONE);
                break;
            }
            _max_irqs(client, data[0]);
            lock_delay(&lock);
            continue;
        }
        if (data[0] == PSLSE_OPEN) {
            if (get_bytes_silent(client->fd, 2, data, timeout,
                                 &(client->abort)) < 0) {
                client_drop(client, PSL_IDLE_CYCLES,
                            CLIENT_NONE);
                debug_msg("_client_loop: client associate failed; could not communicate with socket");
                break;
            }
            _client_associate(client, data[0], (char)data[1]);
            debug_msg("_client_loop: client associated");
            break;
        }
        client->pending = 0;
        break;
        lock_delay(&lock);
    }
    pthread_mutex_unlock(&lock);

    // Terminate thread
    pthread_exit(NULL);
}
Beispiel #8
0
static int _pslse_connect(uint16_t * afu_map, int *fd)
{
	FILE *fp;
	uint8_t buffer[MAX_LINE_CHARS];
	struct sockaddr_in ssadr;
	struct hostent *he;
	char *host, *port_str;
	int port;

	// Get hostname and port of PSLSE server
	DPRINTF("AFU CONNECT\n");
	fp = fopen("pslse_server.dat", "r");
	if (!fp) {
		perror("fopen:pslse_server.dat");
		goto connect_fail;
	}
	do {
		if (fgets((char *)buffer, MAX_LINE_CHARS - 1, fp) == NULL) {
			perror("fgets:pslse_server.dat");
			fclose(fp);
			goto connect_fail;
		}
	}
	while (buffer[0] == '#');
	fclose(fp);
	host = (char *)buffer;
	port_str = strchr((char *)buffer, ':');
	*port_str = '\0';
	port_str++;
	if (!host || !port_str) {
		warn_msg
		    ("cxl_afu_open_dev:Invalid format in pslse_server.data");
		goto connect_fail;
	}
	port = atoi(port_str);

	info_msg("Connecting to host '%s' port %d", host, port);

	// Connect to PSLSE server
	if ((he = gethostbyname(host)) == NULL) {
		herror("gethostbyname");
		puts(host);
		goto connect_fail;
	}
	memset(&ssadr, 0, sizeof(ssadr));
	memcpy(&ssadr.sin_addr, he->h_addr_list[0], he->h_length);
	ssadr.sin_family = AF_INET;
	ssadr.sin_port = htons(port);
	if ((*fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		goto connect_fail;
	}
	ssadr.sin_family = AF_INET;
	ssadr.sin_port = htons(port);
	if (connect(*fd, (struct sockaddr *)&ssadr, sizeof(ssadr)) < 0) {
		perror("connect");
		goto connect_fail;
	}
	strcpy((char *)buffer, "PSLSE");
	buffer[5] = (uint8_t) PSLSE_VERSION_MAJOR;
	buffer[6] = (uint8_t) PSLSE_VERSION_MINOR;
	if (put_bytes_silent(*fd, 7, buffer) != 7) {
		warn_msg("cxl_afu_open_dev:Failed to write to socket!");
		goto connect_fail;
	}
	if (get_bytes_silent(*fd, 1, buffer, -1, 0) < 0) {
		warn_msg("cxl_afu_open_dev:Socket failed open acknowledge");
		close_socket(fd);
		goto connect_fail;
	}
	if (buffer[0] != (uint8_t) PSLSE_CONNECT) {
		warn_msg("cxl_afu_open_dev:PSLSE bad acknowledge");
		close_socket(fd);
		goto connect_fail;
	}
	if (get_bytes_silent(*fd, sizeof(uint16_t), buffer, 1000, 0) < 0) {
		warn_msg("cxl_afu_open_dev:afu_map");
		close_socket(fd);
		goto connect_fail;
	}
	memcpy((char *)afu_map, (char *)buffer, 2);
	*afu_map = (long)ntohs(*afu_map);
	return 0;

 connect_fail:
	errno = ENODEV;
	return -1;
}
Beispiel #9
0
static void *_psl_loop(void *ptr)
{
	struct cxl_afu_h *afu = (struct cxl_afu_h *)ptr;
	uint8_t buffer[MAX_LINE_CHARS];
	uint8_t size;
	uint64_t addr;
	uint16_t value;
	uint32_t lvalue;
	int rc;

	if (!afu)
		fatal_msg("NULL afu passed to libcxl.c:_psl_loop");
	afu->opened = 1;
	while (afu->opened) {
		_delay_1ms();
		// Send any requests to PSLSE over socket
		if (afu->int_req.state == LIBCXL_REQ_REQUEST)
			_req_max_int(afu);
		if (afu->attach.state == LIBCXL_REQ_REQUEST)
			_pslse_attach(afu);
		if (afu->mmio.state == LIBCXL_REQ_REQUEST) {
			switch (afu->mmio.type) {
			case PSLSE_MMIO_MAP:
				_mmio_map(afu);
				break;
			case PSLSE_MMIO_WRITE64:
				_mmio_write64(afu);
				break;
			case PSLSE_MMIO_WRITE32:
				_mmio_write32(afu);
				break;
			case PSLSE_MMIO_EBREAD:
			case PSLSE_MMIO_READ64:
			case PSLSE_MMIO_READ32:	/*fall through */
				_mmio_read(afu);
				break;
			default:
				break;
			}
		}
		// Process socket input from PSLSE
		rc = bytes_ready(afu->fd, 1000, 0);
		if (rc == 0)
			continue;
		if (rc < 0) {
			warn_msg("Socket failure testing bytes_ready");
			_all_idle(afu);
			break;
		}
		if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) {
			warn_msg("Socket failure getting PSL event");
			_all_idle(afu);
			break;
		}
		DPRINTF("PSL EVENT\n");
		switch (buffer[0]) {
		case PSLSE_OPEN:
			if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) {
				warn_msg("Socket failure getting OPEN context");
				_all_idle(afu);
				break;
			}
			afu->context = (uint16_t) buffer[0];
			afu->open.state = LIBCXL_REQ_IDLE;
			break;
		case PSLSE_ATTACH:
			afu->attach.state = LIBCXL_REQ_IDLE;
			break;
		case PSLSE_DETACH:
		        info_msg("detach response from from pslse");
			afu->mapped = 0;
			afu->attached = 0;
			afu->opened = 0;
			afu->open.state = LIBCXL_REQ_IDLE;
			afu->attach.state = LIBCXL_REQ_IDLE;
			afu->mmio.state = LIBCXL_REQ_IDLE;
			afu->int_req.state = LIBCXL_REQ_IDLE;
			break;
		case PSLSE_MAX_INT:
			size = sizeof(uint16_t);
			if (get_bytes_silent(afu->fd, size, buffer, 1000, 0) <
			    0) {
				warn_msg
				    ("Socket failure getting max interrupt acknowledge");
				_all_idle(afu);
				break;
			}
			memcpy((char *)&value, (char *)buffer,
			       sizeof(uint16_t));
			afu->irqs_max = ntohs(value);
			afu->int_req.state = LIBCXL_REQ_IDLE;
			break;
		case PSLSE_QUERY: {
			size = sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint16_t) +
			    sizeof(uint64_t) + sizeof(uint64_t) + sizeof(uint64_t) +  
                            sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t);
			if (get_bytes_silent(afu->fd, size, buffer, 1000, 0) <
			    0) {
				warn_msg("Socket failure getting PSLSE query");
				_all_idle(afu);
				break;
			}
			memcpy((char *)&value, (char *)&(buffer[0]), 2);
			afu->irqs_min = (long)(value);
			memcpy((char *)&value, (char *)&(buffer[2]), 2);
			afu->irqs_max = (long)(value);
                	memcpy((char *)&value, (char *)&(buffer[4]), 2);
			afu->modes_supported = (long)(value);
                	memcpy((char *)&value, (char *)&(buffer[6]), 8);
			afu->mmio_len = (long)(value);
                	memcpy((char *)&value, (char *)&(buffer[14]), 8);
			afu->mmio_off = (long)(value);
                	memcpy((char *)&value, (char *)&(buffer[22]), 8);
			//afu->eb_len = (long)ntohll(value);
			afu->eb_len = (long)(value);
                	memcpy((char *)&value, (char *)&(buffer[30]), 2);
			afu->cr_device = (long)ntohs(value);
                        memcpy((char *)&value, (char *)&(buffer[32]), 2);
			afu->cr_vendor = (long)ntohs(value);
                        memcpy((char *)&lvalue, (char *)&(buffer[34]), 4);
			afu->cr_class = ntohl(lvalue);
			//no better place to put this right now
			afu->prefault_mode = CXL_PREFAULT_MODE_NONE;
			break;
		}
		case PSLSE_MEMORY_READ:
			DPRINTF("AFU MEMORY READ\n");
			if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) {
				warn_msg
				    ("Socket failure getting memory read size");
				_all_idle(afu);
				break;
			}
			size = (uint8_t) buffer[0];
			if (get_bytes_silent(afu->fd, sizeof(uint64_t), buffer,
					     -1, 0) < 0) {
				warn_msg
				    ("Socket failure getting memory read addr");
				_all_idle(afu);
				break;
			}
			memcpy((char *)&addr, (char *)buffer, sizeof(uint64_t));
			addr = ntohll(addr);
			_handle_read(afu, addr, size);
			break;
		case PSLSE_MEMORY_WRITE:
			DPRINTF("AFU MEMORY WRITE\n");
			if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) {
				warn_msg
				    ("Socket failure getting memory write size");
				_all_idle(afu);
				break;
			}
			size = (uint8_t) buffer[0];
			if (get_bytes_silent(afu->fd, sizeof(uint64_t), buffer,
					     -1, 0) < 0) {
				_all_idle(afu);
				break;
			}
			memcpy((char *)&addr, (char *)buffer, sizeof(uint64_t));
			addr = ntohll(addr);
			if (get_bytes_silent(afu->fd, size, buffer, 1000, 0) <
			    0) {
				warn_msg
				    ("Socket failure getting memory write data");
				_all_idle(afu);
				break;
			}
			_handle_write(afu, addr, size, buffer);
			break;
		case PSLSE_MEMORY_TOUCH:
			DPRINTF("AFU MEMORY TOUCH\n");
			if (get_bytes_silent(afu->fd, 1, buffer, 1000, 0) < 0) {
				warn_msg
				    ("Socket failure getting memory touch size");
				_all_idle(afu);
				break;
			}
			size = buffer[0];
			if (get_bytes_silent(afu->fd, sizeof(uint64_t), buffer,
					     -1, 0) < 0) {
				warn_msg
				    ("Socket failure getting memory touch addr");
				_all_idle(afu);
				break;
			}
			memcpy((char *)&addr, (char *)buffer, sizeof(uint64_t));
			addr = ntohll(addr);
			_handle_touch(afu, addr, size);
			break;
		case PSLSE_MMIO_ACK:
			_handle_ack(afu);
			break;
		case PSLSE_INTERRUPT:
			if (_handle_interrupt(afu) < 0) {
				perror("Interrupt Failure");
				goto psl_fail;
			}
			break;
		case PSLSE_AFU_ERROR:
			if (_handle_afu_error(afu) < 0) {
				perror("AFU ERROR Failure");
				goto psl_fail;
			}
			break;
		default:
			break;
		}
	}

 psl_fail:
	afu->attached = 0;
	pthread_exit(NULL);
}
Beispiel #10
0
// Attach to AFU
static void _attach(struct psl *psl, struct client *client)
{
	uint64_t wed;
	uint8_t ack;
	uint8_t buffer[MAX_LINE_CHARS];
	size_t size;

	// FIXME: This only works for dedicate mode
	// might work for afu-directed now - lgt

	// Get wed value from application
	// always do the get
        // pass the wed only for dedicated
	ack = PSLSE_DETACH;
	size = sizeof(uint64_t);
	if (get_bytes_silent(client->fd, size, buffer, psl->timeout,
			     &(client->abort)) < 0) {
	  warn_msg("Failed to get WED value from client");
	  client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE);
	  goto attach_done;
	}

	// but need to save wed if master|slave for future consumption
	// interestingly, I can always save it
	// add to client type.
	memcpy((char *)&wed, (char *)buffer, sizeof(uint64_t));
	// wed came over in be format
	// since we are modeling the psl register here, we should leave it be
#if defined PSL9lite || defined PSL9
	client->wed = wed; // ntohll(wed);
#else
	client->wed = ntohll(wed);
#endif 

	// Send start to AFU
	// only add PSL_JOB_START for dedicated and master clients.
	// send an empty wed in the case of master
	// lgt - new idea:
	// track number of clients in psl
	// if number of clients = 0, then add the start job
	// add llcmd add to client  (loop through clients in send_com)
	// increment number of clients (decrement where we handle the completion of the detach)
	switch (client->type) {
	case 'd':
	  if (psl->attached_clients == 0) {
	    if (add_job(psl->job, PSL_JOB_START, client->wed) != NULL) {
	      // if dedicated, we can ack PSLSE_ATTACH
	      // if master, we might want to wait until after the llcmd add is complete
	      // can I wait here for the START to finish?
	      psl->idle_cycles = PSL_IDLE_CYCLES;
	      ack = PSLSE_ATTACH;
	    }
	  }
	  break;
	case 'm':
	case 's':
	  if (psl->attached_clients < psl->max_clients) {
	    if (psl->attached_clients == 0) {
	      if (add_job(psl->job, PSL_JOB_START, 0L) != NULL) {
		// if master, we might want to wait until after the llcmd add is complete
		// can I wait here for the START to finish?
	      }
	    }
	    psl->idle_cycles = PSL_IDLE_CYCLES;
	    ack = PSLSE_ATTACH;
	  }
	  // running will be set by send/handle_aux2 routines
	  break;
	default:
	  // error?
	  break;
	}

	psl->attached_clients++;
	info_msg( "Attached client context %d: current attached clients = %d: client type = %c\n", client->context, psl->attached_clients, client->type );
	
	// for master and slave send llcmd add
        // master "wed" is 0x0005000000000000 can actually use client->context here as well since context = 0
	// slave "wed" is 0x000500000000hhhh where hhhh is the "handle" from client->context
	// now - about those llcmds :-)
	// put these in a separate list associated with the job?  psl->pe maybe...  or another call to add_job?
	// new routine to job.c?  add_cmd?
	// should a slave know their master?
	if (client->type == 'm' || client->type == 's') {
	        wed = PSL_LLCMD_ADD;
		wed = wed | (uint64_t)client->context;
		// add_pe adds to the client
	        if (add_pe(psl->job, PSL_JOB_LLCMD, wed) != NULL) {
		}
	}

 attach_done:
	if (put_bytes(client->fd, 1, &ack, psl->dbg_fp, psl->dbg_id,
		      client->context) < 0) {
		client_drop(client, PSL_IDLE_CYCLES, CLIENT_NONE);
	}
}