t10_sam.c revision 68941780f0da57f6844d5666a8528421c53133bc
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * CDDL HEADER START
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The contents of this file are subject to the terms of the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Common Development and Distribution License (the "License").
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * You may not use this file except in compliance with the License.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * or http://www.opensolaris.org/os/licensing.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * See the License for the specific language governing permissions
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * and limitations under the License.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * When distributing Covered Code, include this CDDL HEADER in each
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * If applicable, add the following below this CDDL HEADER, with the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * fields enclosed by brackets "[]" replaced with your own identifying
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * information: Portions Copyright [yyyy] [name of copyright owner]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * CDDL HEADER END
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Use is subject to license terms.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#pragma ident "%Z%%M% %I% %E% SMI"
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <aio.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/aio.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/asynch.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <stdio.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <stddef.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <strings.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <pthread.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/types.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/statvfs.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/avl.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/param.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/mman.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/stat.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <fcntl.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <assert.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <errno.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <unistd.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <signal.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/ucontext.h>
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden#include <libzfs.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <assert.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <umem.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <time.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/scsi/generic/sense.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/scsi/generic/status.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include <sys/scsi/generic/inquiry.h>
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include "target.h"
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include "queue.h"
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include "t10.h"
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#include "t10_spc.h"
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson#include "utility.h"
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson/*
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson * []------------------------------------------------------------------[]
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson * | This file contains methods which isolate a transport from device |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | emulation. The first part of the file contains method which are |
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens * | called by the transport to start commands or deliver data. The |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | transport does not know anything about what emulation is being |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | done. The emulation layer receieves cdb's and nows nothing about |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | the transport. This is how it should be. There are a few special |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | cases to deal with transports which have a notion of immediate |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | data, but we're isolating that from the emulation layer. |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Forward declarations
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic Boolean_t t10_find_lun(t10_targ_impl_t *t, int lun, t10_cmd_t *);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic void *lu_runner(void *v);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic Boolean_t t10_lu_initialize(t10_lu_common_t *lu, char *basedir);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic void *t10_aio_done(void *v);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic Boolean_t lu_remove_cmds(msg_t *m, void *v);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic void cmd_common_free(t10_cmd_t *cmd);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic Boolean_t load_params(t10_lu_common_t *lu, char *basedir);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic Boolean_t fallocate(int fd, off64_t len);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic t10_cmd_state_t t10_cmd_state_machine(t10_cmd_t *c, t10_cmd_event_t e);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic void clear_transport(transport_t t);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#ifdef FULL_DEBUG
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic char *state_to_str(t10_cmd_state_t s);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#endif
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic char *event_to_str(t10_cmd_event_t e);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/* ---- These are AVL comparison routines ---- */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic int find_lu_by_num(const void *v1, const void *v2);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic int find_lu_by_guid(const void *v1, const void *v2);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic int find_lu_by_targ(const void *v1, const void *v2);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic int find_cmd_by_addr(const void *v1, const void *v2);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic sam_device_table_t sam_emul_table[];
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Local variables
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic avl_tree_t lu_list;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic pthread_mutex_t lu_list_mutex;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic int lu_id;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtarget_queue_t *mgmtq;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic pthread_mutex_t t10_mutex;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic int t10_num;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic sema_t t10_sema;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Constants
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic const timespec_t usec = {0, 1000};
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_init -- called once at the beginning of time to initialize globals
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_init(target_queue_t *q)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_t junk;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling mgmtq = q;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_init(&lu_list_mutex, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_init(&t10_mutex, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) sema_init(&t10_sema, 0, USYNC_THREAD, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_create(&lu_list, find_lu_by_guid, sizeof (t10_lu_common_t),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling offsetof(t10_lu_common_t, l_all_luns));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_create(&junk, NULL, t10_aio_done, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic void *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_aio_done(void *v)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling aio_result_t *result;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_aio_t *a;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *lu;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling do {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (sema_wait(&t10_sema) != 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM- sema_wait returned error\n");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling continue;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((result = aiowait(NULL)) == (aio_result_t *)-1) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (errno == EINVAL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM- aiowait returned EINVAL\n");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * It's possible for aiowait to return
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * prematurely. So, post another semaphore,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * nanosleep for a usec, and try the wait again.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) sema_post(&t10_sema);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) nanosleep(&usec, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling continue;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling a = (t10_aio_t *)result;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((a != NULL) && (a->a_aio_cmplt != NULL)) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lu = a->a_cmd->c_lu;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_lock(&lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t10_cmd_state_machine(a->a_cmd, T10_Cmd_T4) !=
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling T10_Cmd_S1_Free) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_unlock(&lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*a->a_aio_cmplt)(a->a_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_unlock(&lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM aiowait returned results, but is NULL\n");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*CONSTANTCONDITION*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } while (1);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | Methods called by transports to interface with SAM-3 |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_handle_create -- Create the I_T nexus
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | NOTES:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | max_out can be set to 0 if the transport wishes to wait for all of
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | the data before receiving a DATAOUT message. Fibre Channel will most
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | likely set this to 0, whereas iSCSI will set max_out to the value
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | of MaxRecvDataSegment.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | (*datain_cb)() is called, on the LU thread, when the emulation
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | module needs data *and* t10_send_cmd was called with opt_data_len, but
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | no opt_data.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_targ_handle_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_handle_create(char *targ, char *init, int trans_vers, int tpg, int max_out,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling target_queue_t *tq, void (*datain_cb)(t10_cmd_t *, char *, size_t *))
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_targ_impl_t *t = calloc(1, sizeof (t10_targ_impl_t));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&t10_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_targ_num = t10_num++;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&t10_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_targ_base = strdup(targ);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_i_name = strdup(init);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_trans_vers = trans_vers;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_maxout = max_out;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_to_transport = tq;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_dataout_cb = datain_cb;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Once we actually support two or more transports it would be
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * possible for a collision between the underlying transports
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * target port group values since one wouldn't necessarily know
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * anything about the other. We'll use the upper bits of the
4445fffbbb1ea25fd0e9ea68b9380dd7a6709025Matthew Ahrens * target port group value to separate them.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * If we were to support many transports and with one then running
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * out of bit space we'd need to change the allocation method. Since
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * these values aren't stored anywhere and just used by initiators
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * to determine relative path numbering there's no issue with changing
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * this later if need be.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (trans_vers) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_TRANS_ISCSI:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_tpgt = 0x0000 | tpg;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_TRANS_FC:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_tpgt = 0x8000 | tpg;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_create(&t->s_open_lu, find_lu_by_num, sizeof (t10_lu_impl_t),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling offsetof(t10_lu_impl_t, l_open_targ_node));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_init(&t->s_mutex, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return ((t10_targ_handle_t)t);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_handle_disable(t10_targ_handle_t tp)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_targ_impl_t *t = (t10_targ_impl_t *)tp;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *l;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_shutdown_t s;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling int lu_per_targ = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&t->s_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (avl_numnodes(&t->s_open_lu) != 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling s.t_q = queue_alloc();
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling l = avl_first(&t->s_open_lu);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while (l != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling s.t_lu = l;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(l->l_common->l_from_transports, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling msg_shutdown, (void *)&s);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_free(queue_message_get(s.t_q));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lu_per_targ++;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling l = AVL_NEXT(&t->s_open_lu, l);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_NONIO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x Sent %d shutdown requests for %s\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_targ_num, lu_per_targ, t->s_targ_base);
4445fffbbb1ea25fd0e9ea68b9380dd7a6709025Matthew Ahrens queue_free(s.t_q, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&t->s_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_handle_destroy(t10_targ_handle_t tp)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_targ_impl_t *t = (t10_targ_impl_t *)tp;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *l;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_t *c;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_t *c2free;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling int fast_free = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&t->s_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (avl_numnodes(&t->s_open_lu) != 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while ((l = avl_first(&t->s_open_lu)) != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_remove(&t->s_open_lu, l);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&l->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (avl_numnodes(&l->l_cmds) != 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c = avl_first(&l->l_cmds);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while (c != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c2free = c;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c = AVL_NEXT(&l->l_cmds, c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Only remove those commands which
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * are waiting for a response from
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * the initiator which will not
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * arrive since we're shutting down
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * the connection or have already
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * been canceled by the transport.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Other commands will be freed as
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * they are processed by the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * transport layer or AIO.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((c2free->c_state ==
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling T10_Cmd_S5_Wait) ||
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (c2free->c_state ==
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling T10_Cmd_S6_Freeing)) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling fast_free++;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_state_machine(c2free,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling T10_Cmd_T6);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_NONIO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x FastFree %d ... "
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "Waiting for %d cmds to drain\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_targ_num, fast_free,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_numnodes(&l->l_cmds));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (avl_numnodes(&l->l_cmds) != 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling l->l_wait_for_drain = True;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while (l->l_wait_for_drain == True) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_cond_wait(
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling &l->l_cmd_cond,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling &l->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(avl_numnodes(&l->l_cmds) == 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_NONIO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x Commands drained\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_targ_num);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&l->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_destroy(&l->l_cmds);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(l);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_destroy(&t->s_open_lu);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&t->s_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(t->s_targ_base);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(t->s_i_name);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(t);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_cmd_create -- creates a command pointer
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | If an error occurs, a sense condition buffer will be created that can
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | be sent back to the initiator. The only time this should occur is during
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | LU setup and we've run out of resources like not having enough file
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | descriptors to open the backing store. If the cmdp is NULL, then there's
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | not even enough memory to create a command buffer and the transport
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | should shutdown it's connection a cleanly as possible.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin LingBoolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_create(t10_targ_handle_t t, int lun_number, uint8_t *cdb,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling size_t cdb_len, transport_t trans_id, t10_cmd_t **cmdp)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_t *cmd = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *cmdp = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((cmd = umem_cache_alloc(t10_cmd_cache, UMEM_DEFAULT)) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling bzero(cmd, sizeof (*cmd));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((cmd->c_cdb = malloc(cdb_len)) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_trans_id = trans_id;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *cmdp = cmd;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t10_find_lun((t10_targ_impl_t *)t, lun_number, cmd) == False)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_add(&cmd->c_lu->l_cmds, (void *)cmd);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_state = T10_Cmd_S1_Free;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling bcopy(cdb, cmd->c_cdb, cdb_len);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_cdb_len = cdb_len;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingerror:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd && cmd->c_cdb) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(cmd->c_cdb);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_cdb = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * If we haven't set up the argument pointer, then free the memory
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * that had been allocated to the command.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (*cmdp == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling umem_cache_free(t10_cmd_cache, cmd);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_send_cmd -- send the given command to appropriate LUN emulation
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * | NOTE: emul_id is only provided for DATA_OUT commands (write ops)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | which have multiple phases to complete the request. The emulation
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | module will provide this value when it requests more data to be
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | sent.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin LingBoolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_send(t10_targ_handle_t t, t10_cmd_t *cmd, char *opt_data,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling size_t opt_data_len)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data = opt_data;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data_len = opt_data_len;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_shoot_event(cmd, T10_Cmd_T1);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin LingBoolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_data(t10_targ_handle_t t, t10_cmd_t *cmd, size_t offset, char *data,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling size_t data_len)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data = data;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data_len = data_len;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_offset = offset;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_shoot_event(cmd, T10_Cmd_T4);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * t10_cmd_state_machine -- State machine for T10 commands
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S1: Free - State on instantiation, or after successful
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * completion of command
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S2: In - The command is currently being processed
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * by the lu_runner() thread. Memory associated
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * with the command must not be freed. Can't
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * transition directly to Free state from threads
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * other than lu_runner().
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S3: Trans - Command has been handed off to transport layer
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S4: AIO - Command has been sent to AIO subsystem for
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * further processing.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S5: Wait - Waiting for response from Initiator.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S6: Freeing - Someone other than the lu_runner() has requested
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * that the command be freed and the state was
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * either S2 or S4.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The state transition table is as follows:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * +-----+---+---+---+---+---+
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |S1 |S2 |S3 |S4 |S5 |S6 |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * ---+-----+---+---+---+---+---+
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S1|T5 |T1 | - | - | - | - |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * ---+-----+---+---+---+---+---+
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S2|T5 | - |T2 |T3 | - |T6 |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * ---+-----+---+---+---+---+---+
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S3|T5/6 |T4 | - | - |T7 | |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * ---+-----+---+---+---+---+---+
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S4| |T4 | | | |T6 |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * ---+-----+---+---+---+---+---+
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S5|T6 | - |T4 | - | - | - |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * ---+-----+---+---+---+---+---+
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * S6|T2-4 | | | | | |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * ---+-----+---+---+---+---+---+
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Events definitions:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * -T1: Command has been placed on LU queue for exection.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * -T2: Emulation completed to a point where the transport must
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * take over and send data or CDB response out.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * -T3: Emulation requires data from storage subsystem via asynchronous
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * I/O.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * -T4: One of the following events has caused the transition:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * - Response from initiator to R2T request.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * - Transport has data available to complete dataout request from T10.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * - AIO has completed read/write op.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * -T5: Command complete. Free resources.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * -T6: Cancel command.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * -T7: Transport has sent command to Initiator.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic t10_cmd_state_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_state_machine(t10_cmd_t *c, t10_cmd_event_t e)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *lu = c->c_lu;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /* ---- Callers must already hold the mutex ---- */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(pthread_mutex_trylock(&lu->l_cmd_mutex) != 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (c->c_state) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_S1_Free:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T1:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S2_In;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(c->c_lu->l_common->l_from_transports,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling 0, msg_cmd_send, (void *)c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T5:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S1_Free;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd_common_free(c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (T10_Cmd_S1_Free);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "Illegal event %s on %llx\n", event_to_str(e),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_trans_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_S2_In:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T2:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S3_Trans;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(c->c_lu->l_to_transport, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_msg, (void *)c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T3:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S4_AIO;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) sema_post(&t10_sema);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T5:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S1_Free;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd_common_free(c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (T10_Cmd_S1_Free);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T6:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S6_Freeing;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM: Illegal event %s on %llx\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling event_to_str(e), c->c_trans_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson break;
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_S3_Trans:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T4:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S2_In;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(lu->l_common->l_from_transports, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling msg_cmd_data_out, (void *)c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T5:
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden /*FALLTHRU*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T6:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S1_Free;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd_common_free(c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (T10_Cmd_S1_Free);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden case T10_Cmd_T7:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S5_Wait;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "Illegal event %s -- %llx\n", event_to_str(e),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_trans_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_S4_AIO:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T4:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S2_In;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T6:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S6_Freeing;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "Illegal event %s -- %llx\n", event_to_str(e),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_trans_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_S5_Wait:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson case T10_Cmd_T4:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S3_Trans;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T6:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S1_Free;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd_common_free(c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (T10_Cmd_S1_Free);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson "Illegal event %s -- %llx\n", event_to_str(e),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_trans_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_S6_Freeing:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T2:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T3:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case T10_Cmd_T4:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_state = T10_Cmd_S1_Free;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd_common_free(c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (T10_Cmd_S1_Free);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "Illegal event %s -- %llx\n", event_to_str(e),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_trans_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (c->c_state);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_shoot_event(t10_cmd_t *c, t10_cmd_event_t e)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *lu;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Since the transport may or may not have called into the T10 layer
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson * to allocate a command it's possible that this will be NULL. Instead
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * of requiring every caller of this function to first check if the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * command pointer is null we'll do the check here.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (c == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lu = c->c_lu;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * If t10_cmd_create() fails for some reason other than lack
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * of memory the extended status will be set for the transport
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * to send out. There will not be any LU associated with this
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * command, but the transport will still try to free it.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (!lu) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(e == T10_Cmd_T5);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd_common_free(c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) t10_cmd_state_machine(c, e);
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson (void) pthread_mutex_unlock(&lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_task_mgmt -- handle SAM-3 task management needs
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin LingBoolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_task_mgmt(t10_targ_handle_t t1, TaskOp_t op, int opt_lun, void *tag)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_targ_impl_t *t = (t10_targ_impl_t *)t1;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t search;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *lu;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (op) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case InventoryChange:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((lu = avl_first(&t->s_open_lu)) != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling do {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*CSTYLED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(lu->l_common->l_from_transports,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling 0, msg_targ_inventory_change, (void *)lu);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } while ((lu = AVL_NEXT(&t->s_open_lu, lu)) != NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case ResetTarget:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((lu = avl_first(&t->s_open_lu)) != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling do {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*CSTYLED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(lu->l_common->l_from_transports,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling Q_HIGH, msg_reset_lu, (void *)lu);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } while ((lu = AVL_NEXT(&t->s_open_lu, lu)) != NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case ResetLun:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling search.l_targ_lun = opt_lun;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((lu = avl_find(&t->s_open_lu, (void *)&search, NULL)) !=
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(lu->l_common->l_from_transports,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling Q_HIGH, msg_reset_lu, (void *)lu);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case CapacityChange:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling search.l_targ_lun = opt_lun;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((lu = avl_find(&t->s_open_lu, (void *)&search, NULL)) !=
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(lu->l_common->l_from_transports,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling Q_HIGH, msg_lu_capacity_change,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void *)(uintptr_t)opt_lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_targ_stat -- Return stats on each LU associated with target.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_targ_stat(t10_targ_handle_t t1, char **buf)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_targ_impl_t *t = (t10_targ_impl_t *)t1;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *itl;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char lb[32];
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char *p;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * It's possible for the management interfaces to request stats
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * even though a connection is not up and running.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling itl = avl_first(&t->s_open_lu);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while (itl) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_buf_add_tag(buf, XML_ELEMENT_LUN, Tag_Start);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%d", itl->l_common->l_num);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_buf_add_tag(buf, lb, Tag_String);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%lld", itl->l_cmds_read);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_buf_add(buf, XML_ELEMENT_READCMDS, lb);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%lld", itl->l_cmds_write);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_buf_add(buf, XML_ELEMENT_WRITECMDS, lb);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%lld", itl->l_sects_read);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_buf_add(buf, XML_ELEMENT_READBLKS, lb);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%lld", itl->l_sects_write);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_buf_add(buf, XML_ELEMENT_WRITEBLKS, lb);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (itl->l_common->l_state) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case lu_online:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling p = TGT_STATUS_ONLINE;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case lu_offline:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling p = TGT_STATUS_OFFLINE;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case lu_errored:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling p = TGT_STATUS_ERRORED;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_buf_add(buf, XML_ELEMENT_STATUS, p);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_buf_add_tag(buf, XML_ELEMENT_LUN, Tag_End);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling itl = AVL_NEXT(&t->s_open_lu, itl);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_thick_provision -- fill the backing store with real blocks
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | The backing store is initially created as a hole-y file. The only
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | thing wrong with leaving the files hole-y is that if a system
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | administrator over provisions the storage at some point a client
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | will attempt to write to a block and receive an error unless the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | administrator adds more backing store before that event. Now, depending
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | on the client a write error isn't fatal. However, for file systems
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | like UFS and ZFS, they can not currently deal with getting a write
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | error when it's their metadata and panic. That's not good. The concept
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | of "Thin Provisioning" is relatively new so we'll normally preallocate
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | the space, but have the option of doing the "Thin Provisioning".
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin LingBoolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_thick_provision(char *target, int lun, target_queue_t *q)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_targ_handle_t t;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_t *cmd = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling uint8_t cdb[16]; /* ---- fake buffer ---- */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling diskaddr_t offset = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling size_t size;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling size_t sync_size;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling msg_t *m = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling target_queue_t *rq = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char path[MAXPATHLEN];
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_node_t *n1;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling Boolean_t rval = False;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling struct statvfs fs;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * To guarantee that everything has been setup correctly
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * we'll just use the standard interfaces. Otherwise we'd need
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * to duplicate the code and therefore offer the chance of
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * having something fixed/change in one location that isn't
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * in another. Obvious right?
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((t = t10_handle_create(target, "", 0, 0, 0, q, NULL)) == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS, "STE%x Failed to create handle\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe if (t10_cmd_create(t, lun, cdb, sizeof (cdb), 0, &cmd) == False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS, "STE%x Failed to create cmd\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Attempt to see if there is enough space currently for the LU.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The initialization might still fail with out of space because someone
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * else is consuming space while the initialization is occuring.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Nothing we can do about that.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (fstatvfs(cmd->c_lu->l_common->l_fd, &fs) != 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS, "STE%x statvfs failed for LU\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else if ((fs.f_frsize * fs.f_bfree) < cmd->c_lu->l_common->l_size) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS, "STE%x Not enough space for LU\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (fallocate(cmd->c_lu->l_common->l_fd, cmd->c_lu->l_common->l_size) ==
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The lu_runner will use this buffer to copy data.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling sync_size = 1024 * 1024;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((cmd->c_data = malloc(sync_size)) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while ((offset < cmd->c_lu->l_common->l_size) && (rq == NULL)) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling size = min(cmd->c_lu->l_common->l_size - offset,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling sync_size);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_offset = offset;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data_len = size;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*CSTYLED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(cmd->c_lu->l_common->l_from_transports, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling msg_thick_provo, (void *)cmd);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while ((m = queue_message_get(q)) != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (m->msg_type) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case msg_thick_provo:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((int)(intptr_t)m->msg_data != 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * An error occurred during
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * initialization which mean we
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * need to remove this target.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "STE%x received data "
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "error at 0x%llx\n", lun,
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe offset);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case msg_shutdown:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_NONIO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "---- Thick provo got shutdown\n");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling rq = (target_queue_t *)m->msg_data;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_free(m);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling continue; /* don't use break */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling default:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_free(m);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling offset += size;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_NONIO, "STE%x fallocate worked\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * A forced shutdown is still considered a successful completion.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Write errors and malloc failures constitute a failure.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling rval = True;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /* ---- Completed successfully ---- */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (rq == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Now that the initialization is complete, update the params
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * file to indicate the status is online. Once done, send a
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * message to the LU thread indicating same.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(path, sizeof (path), "%s/%s/%s%d",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling target_basedir, cmd->c_lu->l_targ->s_targ_base, PARAMBASE,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe cmd->c_lu->l_common->l_state = lu_online;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((n1 = tgt_node_find(cmd->c_lu->l_common->l_root,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling XML_ELEMENT_STATUS)) == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "STE%x couldn't find <status>\n", lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_update_value_str(n1, XML_ELEMENT_STATUS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling TGT_STATUS_ONLINE) == False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "STE%x Could update <status> to online\n", lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_dump2file(cmd->c_lu->l_common->l_root, path) ==
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "STE%x failed to dump out params\n", lun);
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(cmd->c_lu->l_common->l_from_transports, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling msg_lu_online, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingerror:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd->c_data != NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(cmd->c_data);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_shoot_event(cmd, T10_Cmd_T5);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_handle_disable(t);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_handle_destroy(t);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (rq != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(rq, 0, msg_shutdown_rsp, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (rval);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | Methods called by emulation modules to interface with SAM-3 |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * trans_cmd_dup -- Duplicate a T10 command buffer
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * During read operations with transports that restrict transfer sizes the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * emulation code has two options.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * (1) It could transfer a chunk of data and wait until the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * transport has sent that out. Notification coming through
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * the callback mechanism. If the command structure is not
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * duplicated it would need to wait since the command structure
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * contains the data pointer and offset values which the transport
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * needs.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * (2) Use this routine to duplicate the command structure such
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * that the emulation layer can send all of the data in chunks
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * without waiting.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * For obvious performance reasons it's best to send all of the chunks
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * without waiting.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * It's expected that the emulation layer will not call this routine for the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * last outgoing packet since the command structure will not be of futher
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * use.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_t *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_cmd_dup(t10_cmd_t *cmd)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_t *c;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens if ((c = umem_cache_alloc(t10_cmd_cache, UMEM_DEFAULT)) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe bcopy(cmd, c, sizeof (*c));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((c->c_cdb = (uint8_t *)malloc(c->c_cdb_len)) == NULL) {
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens free(c);
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens return (False);
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens }
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens bcopy(cmd->c_cdb, c->c_cdb, c->c_cdb_len);
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex);
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens c->c_state = T10_Cmd_S2_In;
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens avl_add(&c->c_lu->l_cmds, (void *)c);
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens return (c);
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens}
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | trans_send_datain -- send data to transport
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | NOTES:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | (1) offset is only valid when a transport has set max_out to a non-zero
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | value.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | (2) The emulation code must free the memory, if it was allocated, when
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | the transport is finished with it. The callback routine is used
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | to provide the emulation code the notification. The callback will
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | not be run on the same thread as the emulation code so appropriate
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | locking may be required by the emulation code.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | (3) If the boolean 'last' is True it means that the transport can
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | assume the data out is finished with a CMD_SUCCESS and no futher
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | communication from the emulation layer will occur.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin LingBoolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_send_datain(t10_cmd_t *c, char *data, size_t data_len, size_t offset,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling void (*callback)(emul_handle_t e), Boolean_t last, emul_handle_t id)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#ifdef FULL_DEBUG
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_IO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LUN%d DataIn 0x%x, offset 0x%x, Last %s\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_lu->l_targ->s_targ_num, c->c_lu->l_common->l_num,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling data_len, offset, last == True ? "true" : "false");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#endif
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_emul_complete = callback;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_emul_id = id;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_data = data;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_data_len = data_len;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_offset = offset;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_last = last;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_msg = msg_cmd_data_in;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_shoot_event(c, T10_Cmd_T2);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | trans_rqst_dataout -- Request data from transport for command
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | If the transport has indicated that data is immediately available,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | which is common for iSCSI, then we'll copy that data into the buffer
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | and call the emulation modules datain function directly.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin LingBoolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_rqst_dataout(t10_cmd_t *cmd, char *data, size_t data_len, size_t offset,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling emul_cmd_t emul_id, void (*callback)(emul_handle_t e))
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling size_t max_xfer;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_emul_complete = callback;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_emul_id = emul_id;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Transport supports immediate data on writes. Currently
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * on the iSCSI protocol has this feature.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * XXX Should all of this be done in the transport?
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd->c_data_len) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#ifdef FULL_DEBUG
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_IO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LUN%d DataOut rqst w/ immed, data_len 0x%x\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_targ->s_targ_num,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_common->l_num, data_len);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#endif
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd->c_data == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * When there's data available, but no buffer it
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * means the transport has decided to leave the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * data on the socket and will read it in
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * when called.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling max_xfer = data_len;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(cmd->c_lu->l_targ->s_dataout_cb != NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*cmd->c_lu->l_targ->s_dataout_cb)(cmd, data,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling &max_xfer);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The data is already in the command buffer so
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * we need to copy it out.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling max_xfer = MIN(cmd->c_data_len - cmd->c_resid,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling data_len);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling bcopy(cmd->c_data + cmd->c_resid, data, max_xfer);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_resid = cmd->c_data_len - max_xfer;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * It's expected since the transport allocated
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * the space, this routine will free the memory
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * instead.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*cmd->c_lu->l_targ->s_dataout_cb)(cmd, data,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling &max_xfer);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data_len = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*cmd->c_lu->l_data)(cmd, emul_id, offset, data, max_xfer);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#ifdef FULL_DEBUG
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_IO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LUN%d DataOut Rqst data_len 0x%x\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_targ->s_targ_num,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_common->l_num, data_len);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#endif
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(cmd->c_data == NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data = data;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data_len = data_len;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_offset = offset;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_resid = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Short cut. There's no reason to call the transport if the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * emulation code hasn't requested any data. If that's the
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * case just call the emulation codes data function.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (data_len == 0)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*cmd->c_lu->l_data)(cmd, emul_id, offset, data, max_xfer);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_msg = msg_cmd_data_rqst;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_shoot_event(cmd, T10_Cmd_T2);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | trans_send_complete -- notify transport command has finished.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | This routine is called either for when the emulation has completed
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | a command which doesn't have a data in phase so we can't use the 'last'
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | flag or there's been an error.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | The sense data is expected to be created by calling spc_create_sense(),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | the memory for that sense data will be freed when the transport calls
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_destroy_cmd().
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | NOTE [1]: If the t10_status equals STATUS_BUSY the command queue for this
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | ITL will be examined. If there are commands in progress the status will
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | be changed to STATUS_QFULL
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | NOTE [2]: Do not access 'cmd' after calling this function. The transport
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | may receive the command, act on it, and then call
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_cmd_shoot_state(cmd, T10_Cmd_T5) before this function returns
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | thereby allowing 'cmd' to be freed and the space reallocated.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_send_complete(t10_cmd_t *cmd, int t10_status)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#ifdef FULL_DEBUG
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling struct scsi_extended_sense e;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#endif
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * XXX Get the exact chapter and verse from the T10 documents.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * translate a STATUS_BUSY to STATUS_QFULL if there are outstanding
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * commands in the queue.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((t10_status == STATUS_BUSY) &&
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (avl_numnodes(&cmd->c_lu->l_cmds) != 0)) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_status = STATUS_QFULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_cmd_status = t10_status;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_last = True;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data_len = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_data = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_msg = msg_cmd_cmplt;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#ifdef FULL_DEBUG
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t10_status != STATUS_GOOD) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd->c_cmd_sense != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling bcopy(&cmd->c_cmd_sense[2], &e, sizeof (e));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LUN%d key_sense=0x%x, "
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "ASC=0x%x, ASCQ=0x%x\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_targ->s_targ_num,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_common->l_num,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling e.es_key, e.es_add_code, e.es_qual_code);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LUN%d key_sense=0x%x\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_targ->s_targ_num,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_common->l_num, t10_status);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#endif
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_shoot_event(cmd, T10_Cmd_T2);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_aiowrite(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_aio_t *taio)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling taio->a_cmd = cmd;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (aiowrite(cmd->c_lu->l_common->l_fd, data, data_len, offset, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling &taio->a_aio) == -1) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling taio->a_aio.aio_return = -1;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*taio->a_aio_cmplt)(taio->a_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_state_machine(cmd, T10_Cmd_T3);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_aioread(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_aio_t *taio)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling taio->a_cmd = cmd;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (aioread(cmd->c_lu->l_common->l_fd, data, data_len, offset, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling &taio->a_aio) == -1) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling taio->a_aio.aio_return = -1;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*taio->a_aio_cmplt)(taio->a_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_state_machine(cmd, T10_Cmd_T3);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | trans_params_area -- return dtype params using a command pointer
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | Lock down the ITL structure from change so that we can cleanly access
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | the params area. This is needed to deal with the transport closing
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | a connection while commands are in flight. When those commands finish
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | cleanup work needs to be done. Yet, the logical unit common area
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | can already be released since it doesn't know there's something to wait
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | for.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingvoid *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_params_area(t10_cmd_t *cmd)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling void *p = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&cmd->c_lu->l_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd->c_lu->l_common != NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling p = cmd->c_lu->l_common->l_dtype_params;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&cmd->c_lu->l_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (p);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | Support routines for Routing and Task Management |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_find_lun -- Locate a per target LUN structure
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | Finds per I_T_L structure. If this is the first time that this structure
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | has been accessed we allocate the structure and add it to the global
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | LUN structure. If that structure has never been accessed before it is
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | created along with a thread to handle the queue.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic Boolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_find_lun(t10_targ_impl_t *t, int lun, t10_cmd_t *cmd)
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *l = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t search;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_index_t wc = 0; /* where common */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_index_t wt = 0; /* where target */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char *guid = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char *str;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char *dataset = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_common_t lc;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_common_t *common = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_node_t *n = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_node_t *n1;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_node_t *targ;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_node_t *ll;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling xmlTextReaderPtr r = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char path[MAXPATHLEN];
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling int xml_fd = -1;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling libzfs_handle_t *zh;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling zfs_handle_t *zfsh;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling Boolean_t okay_to_free = True;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden bzero(&lc, sizeof (lc));
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens /*
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens * Only l_num is used by the AVL search routines so that's
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens * the only thing we'll set.
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens */
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden search.l_targ_lun = lun;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((l = avl_find(&t->s_open_lu, (void *)&search, &wt)) != NULL) {
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden /*
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * This should be the normal fast path. At some point it
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * might be good to look at optimizing this even more.
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * If we know for example that the LUN numbers are sequential
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * and there's fewer than 64 an array of pointers would be
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * even faster than an AVL tree and not take up to much space.
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden */
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden cmd->c_lu = l;
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden return (True);
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden }
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden /*
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens * First access for this I_T_L so we need to allocate space for it.
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens */
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((l = calloc(1, sizeof (*l))) == NULL) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens cmd->c_cmd_status = STATUS_CHECK;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens return (False);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens /*
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens * Initialize the various local fields. Certain fields will not be
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens * initialized until we've got the common LUN pointer.
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens */
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens (void) pthread_mutex_init(&l->l_cmd_mutex, NULL);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens (void) pthread_mutex_init(&l->l_mutex, NULL);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens (void) pthread_cond_init(&l->l_cmd_cond, NULL);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens avl_create(&l->l_cmds, find_cmd_by_addr, sizeof (t10_cmd_t),
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens offsetof(t10_cmd_t, c_cmd_avl));
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens l->l_wait_for_drain = False;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens l->l_to_transport = t->s_to_transport;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens l->l_targ = t;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens l->l_targ_lun = lun;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens targ = NULL;
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ))
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden != NULL) {
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden if ((tgt_find_value_str(targ, XML_ELEMENT_INAME, &str) ==
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden True) && (strcmp(str, t->s_targ_base) == 0)) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens free(str);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens break;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens } else if (str) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens free(str);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens str = NULL;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((ll = tgt_node_next(targ, XML_ELEMENT_LUNLIST, NULL)) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling n = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while ((n = tgt_node_next(ll, XML_ELEMENT_LUN, n)) != NULL) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if (strtol(n->x_value, NULL, 0) == lun)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (n == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /* ---- ACCESS DENIED - INVALID LU IDENTIFIER ---- */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling spc_sense_ascq(cmd, 0x20, 0x9);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_find_value_str(n, XML_ELEMENT_GUID, &guid) == False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Set the targ variable back to NULL to indicate that
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * we don't have an incore copy of the information.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * If the guid is currently 0, we'll update that value
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * and update the ZFS property if targ is not NULL.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Otherwise will update parameter file.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens targ = NULL;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * To locate the common LUN structure we need to find the GUID
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * for this LUN. That's the only parsing this section of code
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * will do to the params file.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(path, sizeof (path), "%s/%s/%s%d",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling target_basedir, t->s_targ_base, PARAMBASE, lun);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens (void) pthread_mutex_lock(&lu_list_mutex);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((xml_fd = open(path, O_RDONLY)) < 0) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens (void) pthread_mutex_unlock(&lu_list_mutex);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens /* ---- ACCESS DENIED - INVALID LU IDENTIFIER ---- */
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_ascq(cmd, 0x20, 0x9);
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden goto error;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens n = NULL;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL,
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden 0)) != NULL) {
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe while (xmlTextReaderRead(r) == 1)
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden if (tgt_node_process(r, &n) == False)
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden break;
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden } else {
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden (void) pthread_mutex_unlock(&lu_list_mutex);
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden goto error;
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden }
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden (void) close(xml_fd);
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe /*
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * Set xml_fd back to -1 so that if an error occurs later we
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * don't attempt to close a file descriptor that another thread
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * might have opened.
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden */
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden xml_fd = -1;
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden xmlTextReaderClose(r);
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden xmlFreeTextReader(r);
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe r = NULL;
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden okay_to_free = True;
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden
b420f3adeb349714478d1a7813d2c0e069d41555Richard Lowe if (tgt_find_value_str(n, XML_ELEMENT_GUID, &guid) == False) {
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden (void) pthread_mutex_unlock(&lu_list_mutex);
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden goto error;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden } else
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens okay_to_free = False;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((strcmp(guid, "0") == 0) || (strcmp(guid, "0x0") == 0)) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens free(guid);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if (util_create_guid(&guid) == False) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens (void) pthread_mutex_unlock(&lu_list_mutex);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens goto error;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((n1 = tgt_node_find(n, XML_ELEMENT_GUID)) == NULL) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens (void) pthread_mutex_unlock(&lu_list_mutex);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens goto error;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if (tgt_update_value_str(n1, XML_ELEMENT_GUID, guid) == False) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens (void) pthread_mutex_unlock(&lu_list_mutex);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (targ != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling str = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_dump2buf(targ, &str);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_find_value_str(targ, XML_ELEMENT_ALIAS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling &dataset) == False ||
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (zh = libzfs_init()) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_ANY)) ==
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling libzfs_fini(zh);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (zfs_prop_set(zfsh,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling zfs_prop_to_name(ZFS_PROP_ISCSIOPTIONS),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling str) != 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling zfs_close(zfsh);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling libzfs_fini(zh);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling zfs_close(zfsh);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens libzfs_fini(zh);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens free(dataset);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(str);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling dataset = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling str = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else if (tgt_dump2file(n, path) == False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&lu_list_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_xml_decode(guid, &lc.l_guid, &lc.l_guid_len) == False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&lu_list_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * See if the common LUN for this GUID already exists.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling wc = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((common = avl_find(&lu_list, (void *)&lc, &wc)) == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The GUID wasn't found, so create a new LUN structure
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * and thread.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((common = calloc(1, sizeof (*common))) == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&lu_list_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_from_transports = queue_alloc();
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_num = lun;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_internal_num = lu_id++;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_guid = lc.l_guid;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_guid_len = lc.l_guid_len;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_fd = -1; /* not open yet */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_mmap = MAP_FAILED;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_root = n;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_root_okay_to_free = okay_to_free;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling n = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_init(&common->l_common_mutex, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(path, sizeof (path), "%s/%s", target_basedir,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_targ_base);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t10_lu_initialize(common, path) == False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_ERRS,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x FAILED to initialize LU %d\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_targ_num, lun);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&lu_list_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_create(&common->l_all_open, find_lu_by_targ,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling sizeof (t10_lu_impl_t),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling offsetof(t10_lu_impl_t, l_open_lu_node));
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_insert(&lu_list, (void *)common, wc);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_create(&common->l_thr_id, NULL, lu_runner,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void *)common);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_NONIO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LU[%d.%d] Created new LU thread 0x%x\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t->s_targ_num, common->l_internal_num, common->l_num,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_thr_id);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden } else {
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * If there's a common LU structure already we free
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * the guid which was created for the search. If an error
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * occurs the guid space will be freed in the error handling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * code. If a new LU is created though we don't free the guid
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * since the LU needs the information.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(lc.l_guid);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * A similar condition exists with the xml tree. If there's
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * already a common LU then this node *may* have been created
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * here if it's not a ZVOL. If it is a ZVOL tree then it will
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * have the same address as that found in l_root so don't
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * free it.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (okay_to_free == True) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_node_free(n);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling n = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lc.l_guid = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_NONIO,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x Found existing LU[%d.%d]\n", t->s_targ_num,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling common->l_internal_num, common->l_num);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&common->l_common_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) avl_find(&common->l_all_open, (void *)l, &wc);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_insert(&common->l_all_open, (void *)l, wc);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&common->l_common_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&lu_list_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Now add this I_T_L to the targets list of open LUNs so that
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * in the future we can get access through the AVL tree.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * We wait to add the LU to the target list until now so that we don't
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * have to delete the node in case an error occurs.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling avl_insert(&t->s_open_lu, (void *)l, wt);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&l->l_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling l->l_common = common;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&l->l_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The common LU thread is responsible for filling in the command
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * functions and table.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(common->l_from_transports, 0, msg_lu_add, (void *)l);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(guid);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu = l;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingerror:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_cmd_status = STATUS_CHECK;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (guid)
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson free(guid);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (xml_fd != -1)
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson (void) close(xml_fd);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (r) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling xmlTextReaderClose(r);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling xmlFreeTextReader(r);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (n)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling tgt_node_free(n);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (l)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(l);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (lc.l_guid)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(lc.l_guid);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (common)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(common);
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson if (dataset)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(dataset);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilsonstatic Boolean_t
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_lu_initialize(t10_lu_common_t *lu, char *basedir)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char *str = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling int dtype;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (load_params(lu, basedir) == False)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_find_value_str(lu->l_root, XML_ELEMENT_DTYPE, &str) == True) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling for (dtype = 0; sam_emul_table[dtype].t_type_name != NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling dtype++) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (strcmp(sam_emul_table[dtype].t_type_name,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling str) == 0) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lu->l_dtype = dtype;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((*sam_emul_table[dtype].t_common_init)(lu)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling == False)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling else
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling break;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(str);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling goto error;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (True);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingerror:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (str != NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling free(str);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (False);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling}
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []----
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | lu_runner -- The workhorse for each LU
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | This routine is the guts of the Task Router and Task Set for SAM-3.
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson * []----
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic void *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Linglu_runner(void *v)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling{
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson t10_lu_common_t *lu = (t10_lu_common_t *)v;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling msg_t *m;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_lu_impl_t *itl;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_cmd_t *cmd;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling char *data;
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson char *path;
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson size_t data_len;
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson size_t new_size;
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson size_t offset;
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson ssize_t cc;
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson void *provo_err;
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson t10_shutdown_t *s;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling t10_aio_t *a;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling util_title(mgmtq, Q_STE_NONIO, lu->l_internal_num, "Start LU");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while ((m = queue_message_get(lu->l_from_transports)) != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (m->msg_type) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling case msg_cmd_send:
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd = (t10_cmd_t *)m->msg_data;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (cmd->c_lu->l_status) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling spc_sense_create(cmd, cmd->c_lu->l_status, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling spc_sense_ascq(cmd, cmd->c_lu->l_asc,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_ascq);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Clear out the per LU values before
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * calling trans_send_complete(). It's
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * possible for the transport to handle
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * this command and free it before returning.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_status = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_asc = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling cmd->c_lu->l_ascq = 0;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling trans_send_complete(cmd, STATUS_CHECK);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } else {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lu->l_curr = cmd;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*cmd->c_lu->l_cmd)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (cmd, cmd->c_cdb, cmd->c_cdb_len);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling lu->l_curr = NULL;
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling }
break;
case msg_cmd_data_out:
cmd = (t10_cmd_t *)m->msg_data;
data = cmd->c_data;
data_len = cmd->c_data_len;
offset = cmd->c_offset;
/*
* We clear the c_data_len here because if the
* emulation routine processes the data and still
* needs more it will call trans_rqst_datain()
* which will look at c_data_len to see if there
* was immediate data available from the transport.
* In this case we've already processed the data
* and need to request more from the transport.
* c_data is set to NULL because there's an assert
* in trans_rqst_datain() checking that c_data is
* indeed null.
*/
cmd->c_data_len = 0;
cmd->c_data = NULL;
lu->l_curr = cmd;
(*cmd->c_lu->l_data)(cmd, cmd->c_emul_id,
offset, data, data_len);
lu->l_curr = NULL;
break;
case msg_lu_aio_done:
a = (t10_aio_t *)m->msg_data;
(*a->a_aio_cmplt)(a->a_id);
break;
case msg_lu_add:
itl = (t10_lu_impl_t *)m->msg_data;
(*sam_emul_table[lu->l_dtype].t_per_init)(itl);
break;
case msg_reset_lu:
queue_reset(lu->l_from_transports);
(void) pthread_mutex_lock(&lu->l_common_mutex);
itl = avl_first(&lu->l_all_open);
do {
/*
* The current implementation is that we
* have a shared queue for each LU. That means
* if we reset a LU all I_T nexus' must
* receive a CHECK_CONDITION on their next
* command.
*/
(*sam_emul_table[lu->l_dtype].t_per_fini)(itl);
(*sam_emul_table[lu->l_dtype].t_per_init)(itl);
itl = AVL_NEXT(&lu->l_all_open, itl);
} while (itl != NULL);
(void) pthread_mutex_unlock(&lu->l_common_mutex);
break;
case msg_shutdown:
s = (t10_shutdown_t *)m->msg_data;
itl = s->t_lu;
(void) pthread_mutex_lock(&lu_list_mutex);
(void) pthread_mutex_lock(&lu->l_common_mutex);
assert(avl_find(&lu->l_all_open, (void *)itl, NULL) !=
NULL);
avl_remove(&lu->l_all_open, (void *)itl);
queue_walker_free(lu->l_from_transports,
lu_remove_cmds, (void *)itl);
(*sam_emul_table[lu->l_dtype].t_per_fini)(itl);
/*
* Don't remove reference to l_common area until after
* the emulation routines are finished since they
* are likely to reference l_dtype_params.
*/
(void) pthread_mutex_lock(&itl->l_mutex);
itl->l_common = NULL;
(void) pthread_mutex_unlock(&itl->l_mutex);
queue_message_set(s->t_q, 0, msg_shutdown_rsp,
(void *)(uintptr_t)itl->l_targ_lun);
if (avl_numnodes(&lu->l_all_open) == 0) {
queue_prt(mgmtq, Q_STE_NONIO,
"LU_%x No remaining targets for LU(%d)\n",
lu->l_internal_num, lu->l_fd);
if (lu->l_mmap != MAP_FAILED)
(void) munmap(lu->l_mmap,
lu->l_size);
if (close(lu->l_fd) != 0)
queue_prt(mgmtq, Q_STE_ERRS,
"LU_%x Failed to close fd, "
"errno=%d\n", lu->l_internal_num,
errno);
/*CSTYLED*/
(*sam_emul_table[lu->l_dtype].t_common_fini)(lu);
avl_remove(&lu_list, (void *)lu);
util_title(mgmtq, Q_STE_NONIO,
lu->l_internal_num, "End LU");
queue_free(lu->l_from_transports, NULL);
(void) pthread_mutex_unlock(
&lu->l_common_mutex);
(void) pthread_mutex_unlock(&lu_list_mutex);
if (lu->l_root_okay_to_free == True)
tgt_node_free(lu->l_root);
free(lu->l_pid);
free(lu->l_vid);
free(lu->l_guid);
free(lu);
queue_message_free(m);
queue_message_set(mgmtq, 0, msg_pthread_join,
(void *)(uintptr_t)pthread_self());
pthread_exit(NULL);
}
(void) pthread_mutex_unlock(&lu->l_common_mutex);
(void) pthread_mutex_unlock(&lu_list_mutex);
break;
case msg_targ_inventory_change:
itl = (t10_lu_impl_t *)m->msg_data;
itl->l_status = KEY_UNIT_ATTENTION;
/*
* SPC-3 revision 21c, section 4.5.6, Table 28
* When LU inventory changes need to report
* a REPORTED LUNS DATA HAS CHANGED event.
*/
itl->l_asc = 0x3f;
itl->l_ascq = 0x0e;
queue_prt(mgmtq, Q_STE_NONIO,
"LU_%x Received InventoryChange for %d\n",
lu->l_internal_num, itl->l_common->l_num);
break;
case msg_thick_provo:
cmd = (t10_cmd_t *)m->msg_data;
if (lu->l_mmap != MAP_FAILED) {
/*
* If the file at c_offset is currently
* unallocated we'll read in that buffer
* which will be zeros and then write it
* back out which will force the underlying
* filesystem to allocate the blocks.
* If someone has already issued a write
* to this area we'll then just cause a
* useless, but safe read/write to occur.
*/
lu->l_curr = cmd;
lu->l_curr_provo = True;
bcopy((char *)lu->l_mmap + cmd->c_offset,
cmd->c_data, cmd->c_data_len);
cmd->c_lu->l_cmds_read++;
cmd->c_lu->l_sects_read +=
cmd->c_data_len / 512;
bcopy(cmd->c_data,
(char *)lu->l_mmap + cmd->c_offset,
cmd->c_data_len);
cmd->c_lu->l_cmds_write++;
cmd->c_lu->l_sects_write +=
cmd->c_data_len / 512;
lu->l_curr = NULL;
lu->l_curr_provo = False;
provo_err = 0;
} else {
if ((cc = pread(lu->l_fd, cmd->c_data,
cmd->c_data_len, cmd->c_offset)) < 0) {
queue_prt(mgmtq, Q_STE_ERRS,
"LU_%x pread errno=%d\n",
lu->l_num, errno);
} else if (pwrite(lu->l_fd, cmd->c_data, cc,
cmd->c_offset) != cc) {
queue_prt(mgmtq, Q_STE_ERRS,
"LU_%x pwrite errno=%d\n",
lu->l_num, errno);
}
provo_err = (cc == cmd->c_data_len) ?
(void *)0 : (void *)1;
}
/*
* acknowledge this op and wait for next
*/
queue_message_set(cmd->c_lu->l_to_transport, 0,
msg_thick_provo, provo_err);
break;
case msg_lu_capacity_change:
new_size = lseek(lu->l_fd, 0, SEEK_END);
queue_prt(mgmtq, Q_STE_NONIO,
"LU_%x Capacity Change from 0x%llx to 0x%llx\n",
lu->l_internal_num, lu->l_size, new_size);
if ((path = malloc(MAXPATHLEN)) == NULL)
break;
(void) snprintf(path, MAXPATHLEN, "%s/%s",
target_basedir, itl->l_targ->s_targ_base);
(void) load_params(lu, path);
free(path);
(*sam_emul_table[lu->l_dtype].t_task_mgmt)(lu,
CapacityChange);
(void) pthread_mutex_lock(&lu->l_common_mutex);
itl = avl_first(&lu->l_all_open);
while (itl != NULL) {
itl->l_status = KEY_UNIT_ATTENTION;
itl->l_asc = SPC_ASC_CAP_CHANGE;
itl->l_ascq = SPC_ASCQ_CAP_CHANGE;
itl = AVL_NEXT(&lu->l_all_open, itl);
}
(void) pthread_mutex_unlock(&lu->l_common_mutex);
break;
case msg_lu_online:
queue_prt(mgmtq, Q_STE_NONIO,
"LU_%x Received online event\n",
lu->l_internal_num);
if ((path = malloc(MAXPATHLEN)) == NULL)
break;
(void) pthread_mutex_lock(&lu->l_common_mutex);
itl = avl_first(&lu->l_all_open);
(void) pthread_mutex_unlock(&lu->l_common_mutex);
(void) snprintf(path, MAXPATHLEN, "%s/%s",
target_basedir, itl->l_targ->s_targ_base);
(void) load_params(lu, path);
free(path);
(*sam_emul_table[lu->l_dtype].t_task_mgmt)(lu,
DeviceOnline);
(void) pthread_mutex_lock(&lu->l_common_mutex);
itl = avl_first(&lu->l_all_open);
while (itl != NULL) {
(*sam_emul_table[lu->l_dtype].t_per_init)(itl);
itl = AVL_NEXT(&lu->l_all_open, itl);
}
(void) pthread_mutex_unlock(&lu->l_common_mutex);
break;
}
queue_message_free(m);
}
return (NULL);
}
/*
* []----
* | lu_buserr_handler -- deal with SIGBUS on mmap'd files
* |
* | Normally SIGBUS's are a real bad thing. With this project, which uses
* | mmap'd files that start out as hole-y, can represent more space than
* | the underlying storage has available. This is good and considered a
* | feature for "Thin Provisioning". However, this means that if the
* | administrator isn't on the ball the storage can fill up. Because of the
* | asynchronous nature of writing to a mmap'd file the OS will send a SIGBUS
* | to the thread which caused the problem. The thread will then locate its
* | data structure and in turn signal the initiator that a problem occurred.
* | Since we can't restart we're we left off because the out of space
* | condition is still present another thread is started to handle other
* | commands for the logical unit. The current thread will then exit.
* |
* | NOTE:
* | If for any reason this routine doesn't find what's it's expecting to
* | assert() will be called to create a core. This routine will only recover
* | from the expected case of a SIGBUS, otherwise something real bad has
* | happened and we need to see the core.
* []----
*/
/*ARGSUSED*/
void
lu_buserr_handler(int sig, siginfo_t *sip, void *v)
{
t10_lu_common_t *lu;
pthread_t id = pthread_self();
char *fa;
if (pthread_mutex_trylock(&lu_list_mutex) != 0) {
assert(0);
}
lu = avl_first(&lu_list);
while (lu != NULL) {
if (lu->l_thr_id == id)
break;
lu = AVL_NEXT(&lu_list, lu);
}
(void) pthread_mutex_unlock(&lu_list_mutex);
if ((lu == NULL) || (lu->l_curr == NULL)) {
queue_prt(mgmtq, Q_STE_ERRS,
"SAM%x BUS ERROR and couldn't find logical unit\n",
lu->l_num);
assert(0);
#ifdef NDEBUG
return;
#endif
}
if (lu->l_mmap == MAP_FAILED) {
queue_prt(mgmtq, Q_STE_ERRS,
"SAM%x BUS ERROR and device not mmap'd\n", lu->l_num);
assert(0);
#ifdef NDEBUG
return;
#endif
}
fa = (char *)sip->__data.__fault.__addr;
if ((fa < (char *)lu->l_mmap) ||
(fa > ((char *)lu->l_mmap + lu->l_size))) {
queue_prt(mgmtq, Q_STE_ERRS,
"SAM%x BUS ERROR occurred outsize of mmap bounds\n",
lu->l_num);
assert(0);
#ifdef NDEBUG
return;
#endif
}
if (lu->l_curr_provo == True) {
lu->l_curr_provo = False;
queue_message_set(lu->l_curr->c_lu->l_to_transport, 0,
msg_thick_provo, (void *)1);
} else {
spc_sense_create(lu->l_curr, KEY_MEDIUM_ERROR, 0);
spc_sense_ascq(lu->l_curr, SPC_ASC_WRITE_ERROR,
SPC_ASCQ_WRITE_ERROR);
trans_send_complete(lu->l_curr, STATUS_CHECK);
}
queue_prt(mgmtq, Q_STE_ERRS,
"SAM%x Caught an out-of-space issue\n", lu->l_num);
/*
* Now restart another thread to pick up where we've left off with
* processing commands for this logical unit.
*/
(void) pthread_create(&lu->l_thr_id, NULL, lu_runner, (void *)lu);
pthread_exit((void *)0);
}
/*
* []----
* | lu_remove_cmds -- look for and free commands for a given ITL
* []----
*/
static Boolean_t
lu_remove_cmds(msg_t *m, void *v)
{
t10_lu_impl_t *lu = (t10_lu_impl_t *)v;
t10_cmd_t *c;
switch (m->msg_type) {
case msg_cmd_send:
case msg_cmd_data_out:
c = (t10_cmd_t *)m->msg_data;
if (c->c_lu == lu) {
queue_prt(mgmtq, Q_STE_NONIO,
"SAM%x LUN %d, removed command during lu_remove\n",
c->c_lu->l_targ->s_targ_num, lu->l_common->l_num);
t10_cmd_shoot_event(c, T10_Cmd_T5);
return (True);
}
break;
}
return (False);
}
/*
* []----
* | load_params -- load parameters and open LU backing store
* |
* | This routine can be called multiple times and will free and release
* | previous resources.
* []----
*/
static Boolean_t
load_params(t10_lu_common_t *lu, char *basedir)
{
char file[MAXPATHLEN];
char *str;
int oflags = O_RDWR|O_LARGEFILE|O_NDELAY;
Boolean_t mmap_lun = True;
tgt_node_t *node = NULL;
int version_maj = XML_VERS_LUN_MAJ;
int version_min = XML_VERS_LUN_MIN;
/*
* Clean up from previous call to this function. This occurs if
* the LU has grown since it was last opened.
*/
if (lu->l_mmap != MAP_FAILED)
munmap(lu->l_mmap, lu->l_size);
if (lu->l_fd != -1)
close(lu->l_fd);
node = lu->l_root;
if (validate_version(node, &version_maj, &version_min) == False)
fprintf(stderr, "Failed version check\n");
if (tgt_find_value_str(node, XML_ELEMENT_PID, &lu->l_pid) == False)
goto error;
if (tgt_find_value_str(node, XML_ELEMENT_VID, &lu->l_vid) == False)
goto error;
/*
* If there's no <status> tag it just means this is an older param
* file and there's no need to treat it as an error. Just mark
* the device as online.
*/
if (tgt_find_value_str(node, XML_ELEMENT_STATUS, &str) == True) {
if (strcmp(str, TGT_STATUS_ONLINE) == 0)
lu->l_state = lu_online;
else if (strcmp(str, TGT_STATUS_OFFLINE) == 0)
lu->l_state = lu_offline;
else if (strcmp(str, TGT_STATUS_ERRORED) == 0)
lu->l_state = lu_errored;
free(str);
} else
lu->l_state = lu_online;
/*
* If offline, we need to check to see if there's an initialization
* thread running for this lun. If not, start one.
*/
if ((lu->l_state == lu_offline) &&
(thick_provo_chk_thr(strrchr(basedir, '/') + 1, lu->l_num) ==
False)) {
queue_prt(mgmtq, Q_STE_NONIO,
"LU_%d No initialization thread running\n", lu->l_num);
if (thin_provisioning == False) {
thick_provo_t *tp;
pthread_t junk;
if ((tp = calloc(1, sizeof (*tp))) != NULL) {
tp->targ_name = strdup(strrchr(basedir, '/')) +
1;
tp->lun = lu->l_num;
tp->q = queue_alloc();
(void) pthread_create(&junk, NULL,
thick_provo_start, tp);
/* ---- wait for start message ---- */
queue_message_free(queue_message_get(tp->q));
}
}
}
/*
* The default is to disable the fast write acknowledgement which
* can be overridden in a couple of ways. First, see if the global
* fast-write-ack is enabled, then check the per logical unit flags.
* The per LU bit is settable via a SCSI command.
*/
lu->l_fast_write_ack = False;
(void) tgt_find_value_boolean(main_config, XML_ELEMENT_FAST,
&lu->l_fast_write_ack);
(void) tgt_find_value_boolean(node, XML_ELEMENT_FAST,
&lu->l_fast_write_ack);
if (lu->l_fast_write_ack == False)
oflags |= O_SYNC;
/*
* Object-based Storage Devices currently use directories to
* represent the partitions and files in those directories to
* represent user objects and collections. Therefore, there's
* not just a single file to be opened, but potentially thousands.
* Therefore, stop here if we've got an OSD dtype.
*/
if (tgt_find_value_str(node, XML_ELEMENT_DTYPE, &str) == False)
goto error;
if (strcmp(str, TGT_TYPE_OSD) == 0) {
free(str);
return (True);
} else
free(str);
if (tgt_find_value_str(node, XML_ELEMENT_BACK, &str) == True) {
lu->l_fd = open(str, oflags);
free(str);
if (lu->l_fd == -1)
goto error;
} else {
(void) snprintf(file, sizeof (file), "%s/%s%d", basedir,
LUNBASE, lu->l_num);
if ((lu->l_fd = open(file, oflags)) == -1)
goto error;
}
#ifndef _LP64
/*
* Since the address space is so limited on 32bit machines
* disable mmap'ing the file by default.
*/
mmap_lun = False;
#endif
(void) tgt_find_value_boolean(node, XML_ELEMENT_MMAP_LUN, &mmap_lun);
if (tgt_find_value_str(node, XML_ELEMENT_SIZE, &str) == True) {
lu->l_size = strtoll(str, NULL, 0) * 512LL;
free(str);
} else
goto error;
if (mmap_lun == True) {
/*
* st_size will be wrong if the device is a block device
* but that's okay since you can't mmap in a block device.
* A block device will fall back to using AIO operations.
*/
lu->l_mmap = mmap(0, lu->l_size, PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_ALIGN, lu->l_fd, 0);
} else {
/*
* Since the default case will be to mmap
* in all files someone has asked that this
* lun not be mmap.
*/
lu->l_mmap = MAP_FAILED;
}
return (True);
error:
if (lu->l_pid) {
free(lu->l_pid);
lu->l_pid = NULL;
}
if (lu->l_vid) {
free(lu->l_vid);
lu->l_vid = NULL;
}
if (lu->l_fd != -1) {
(void) close(lu->l_fd);
lu->l_fd = -1;
}
return (False);
}
/*
* []----
* | cmd_common_free -- frees data stored in the cmd
* |
* | NOTE: The mutex which protects c_state must be held when this routine
* | is called if there's a LU associated with this command.
* []----
*/
static void
cmd_common_free(t10_cmd_t *c)
{
t10_lu_impl_t *lu = c->c_lu;
if (lu) {
assert(pthread_mutex_trylock(&lu->l_cmd_mutex) != 0);
avl_remove(&lu->l_cmds, c);
}
c->c_state = T10_Cmd_S1_Free;
c->c_data = 0;
c->c_data_len = 0;
clear_transport(c->c_trans_id);
if (c->c_emul_complete != NULL) {
(*c->c_emul_complete)(c->c_emul_id);
c->c_emul_complete = NULL;
}
if (c->c_cdb) {
free(c->c_cdb);
c->c_cdb = NULL;
}
if (c->c_cmd_sense) {
free(c->c_cmd_sense);
c->c_cmd_sense = NULL;
}
if (lu && (lu->l_wait_for_drain == True) &&
(avl_numnodes(&lu->l_cmds) == 0)) {
lu->l_wait_for_drain = False;
(void) pthread_cond_signal(&lu->l_cmd_cond);
}
umem_cache_free(t10_cmd_cache, c);
}
/*
* clear_transport -- Remove the transports reference to the T10 command
*
* This should be a function pointer stored in the t10_lu_impl structure.
* The only reason it's not, is I wish to wait until we know a little more
* about the FC transport. There may be some other callbacks required for that
* transport and if so, I'll need to define a new method for passing in
* the callbacks to the t10_create_handle. The easiest way would probably
* have a structure. I'm concerned about supporting different versions, so
* wish to think about it some more before implementing.
*
* This function can be called on either the transport thread or the t10
* thread.
*/
static void
clear_transport(transport_t t)
{
iscsi_cmd_t *c = (iscsi_cmd_t *)t;
if (c)
c->c_t10_cmd = NULL;
}
/*
* []----
* | fallocate -- allocate blocks for file via file system interface
* |
* | This is a faster approach to allocating the blocks for a file.
* | Instead of reading and then writing each block which will force the
* | file system to allocate the data we simply ask the file system to
* | allocate the space. Unfortunately not all file systems support this
* | feature.
* []----
*/
static Boolean_t
fallocate(int fd, off64_t len)
{
#ifdef FALLOCATE_SUPPORTED
#if defined(_LARGEFILE64_SOURCE) && !defined(_LP64)
struct flock64 lck;
lck.l_whence = 0;
lck.l_start = 0;
lck.l_len = len;
lck.l_type = F_WRLCK;
if (fcntl(fd, F_ALLOCSP64, &lck) == -1)
return (False);
else
return (True);
#else
struct flock lck;
lck.l_whence = 0;
lck.l_start = 0;
lck.l_len = len;
lck.l_type = F_WRLCK;
if (fcntl(fd, F_ALLOCSP, &lck) == -1)
return (False);
else
return (True);
#endif
#else
return (False);
#endif
}
/*
* []----
* | find_lu_by_num -- AVL comparison which looks at LUN
* []----
*/
static int
find_lu_by_num(const void *v1, const void *v2)
{
t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1;
t10_lu_impl_t *l2 = (t10_lu_impl_t *)v2;
if (l1->l_targ_lun < l2->l_targ_lun)
return (-1);
if (l1->l_targ_lun > l2->l_targ_lun)
return (1);
return (0);
}
/*
* []----
* | find_lu_by_guid -- AVL comparison which looks at GUID
* []----
*/
static int
find_lu_by_guid(const void *v1, const void *v2)
{
t10_lu_common_t *l1 = (t10_lu_common_t *)v1;
t10_lu_common_t *l2 = (t10_lu_common_t *)v2;
int i;
if (l1->l_guid_len != l2->l_guid_len) {
return ((l1->l_guid_len < l2->l_guid_len) ? -1 : 1);
}
for (i = 0; i < l1->l_guid_len; i++) {
if (l1->l_guid[i] != l2->l_guid[i]) {
return ((l1->l_guid[i] < l2->l_guid[i]) ? -1 : 1);
}
}
return (0);
}
/*
* []----
* | find_lu_by_targ -- AVL comparison which looks at the target
* |
* | NOTE:
* | The target value is the memory address of the per target structure.
* | Therefore, it's not persistent in any manner, nor can any association
* | be made between the target value and the initiator. It will be unique
* | however which is all that we're looking for.
* []----
*/
static int
find_lu_by_targ(const void *v1, const void *v2)
{
t10_lu_impl_t *l1 = (t10_lu_impl_t *)v1;
t10_lu_impl_t *l2 = (t10_lu_impl_t *)v2;
if ((uint64_t)(uintptr_t)l1->l_targ < (uint64_t)(uintptr_t)l2->l_targ)
return (-1);
else if ((uint64_t)(uintptr_t)l1->l_targ >
(uint64_t)(uintptr_t)l2->l_targ)
return (1);
else
return (0);
}
/*
* []----
* | find_cmd_by_addr -- AVL comparison using the simplist of methods
* []----
*/
static int
find_cmd_by_addr(const void *v1, const void *v2)
{
uint64_t cmd1 = (uint64_t)(uintptr_t)v1;
uint64_t cmd2 = (uint64_t)(uintptr_t)v2;
if (cmd1 < cmd2)
return (-1);
else if (cmd1 > cmd2)
return (1);
else
return (0);
}
/*ARGSUSED*/
static Boolean_t
sam_common_init(t10_lu_common_t *t)
{
assert(0);
return (False);
}
/*ARGSUSED*/
static void
sam_common_fini(t10_lu_common_t *t)
{
assert(0);
}
#ifdef FULL_DEBUG
static char *
state_to_str(t10_cmd_state_t s)
{
switch (s) {
case T10_Cmd_S1_Free: return ("FREE");
case T10_Cmd_S2_In: return ("IN");
case T10_Cmd_S3_Trans: return ("TRANS");
case T10_Cmd_S4_AIO: return ("AIO");
case T10_Cmd_S5_Wait: return ("WAIT");
case T10_Cmd_S6_Freeing: return ("FREEING");
}
return ("Invalid State");
}
#endif
static char *
event_to_str(t10_cmd_event_t e)
{
switch (e) {
case T10_Cmd_T1: return ("T1");
case T10_Cmd_T2: return ("T2");
case T10_Cmd_T3: return ("T3");
case T10_Cmd_T4: return ("T4");
case T10_Cmd_T5: return ("T5");
case T10_Cmd_T6: return ("T6");
case T10_Cmd_T7: return ("T7");
}
return ("Invalid Event");
}
/*ARGSUSED*/
static void
sam_per_init(t10_lu_impl_t *t)
{
assert(0);
}
/*ARGSUSED*/
static void
sam_per_fini(t10_lu_impl_t *t)
{
assert(0);
}
/*ARGSUSED*/
static void
sam_task_mgmt(t10_lu_common_t *t, TaskOp_t op)
{
assert(0);
}
static sam_device_table_t sam_emul_table[] = {
/* 0x00: DTYPE_DIRECT */
{ sbc_common_init, sbc_common_fini, sbc_per_init, sbc_per_fini,
sbc_task_mgmt, TGT_TYPE_DISK },
/* 0x01: DTYPE_SEQUENTIAL */
{ ssc_common_init, ssc_common_fini, ssc_per_init, ssc_per_fini,
ssc_task_mgmt, TGT_TYPE_TAPE },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
/* 0x11: DTYPE_OSD */
{ osd_common_init, osd_common_fini, osd_per_init, osd_per_fini,
osd_task_mgmt, TGT_TYPE_OSD },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
{ sam_common_init, sam_common_fini, sam_per_init, sam_per_fini,
sam_task_mgmt, TGT_TYPE_INVALID },
/* 0x1f: DTYPE_UNKNOWN */
{ raw_common_init, raw_common_fini, raw_per_init, raw_per_fini,
raw_task_mgmt, TGT_TYPE_RAW },
/* End-of-Table marker */
{ 0, 0, 0, 0, 0, NULL }
};