t10_sam.c revision 68941780f0da57f6844d5666a8528421c53133bc
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * CDDL HEADER START
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 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * See the License for the specific language governing permissions
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * and limitations under the License.
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 * CDDL HEADER END
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Use is subject to license terms.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling#pragma ident "%Z%%M% %I% %E% SMI"
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 * Forward declarations
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 load_params(t10_lu_common_t *lu, char *basedir);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic t10_cmd_state_t t10_cmd_state_machine(t10_cmd_t *c, 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 Ling * Local variables
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Constants
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_init -- called once at the beginning of time to initialize globals
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 (void) pthread_create(&junk, NULL, t10_aio_done, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic void *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM- sema_wait returned error\n");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((result = aiowait(NULL)) == (aio_result_t *)-1) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM- aiowait returned EINVAL\n");
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 "SAM aiowait returned results, but is NULL\n");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*CONSTANTCONDITION*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } while (1);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | Methods called by transports to interface with SAM-3 |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_handle_create -- Create the I_T nexus
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 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 t10_targ_impl_t *t = calloc(1, sizeof (t10_targ_impl_t));
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 avl_create(&t->s_open_lu, find_lu_by_num, sizeof (t10_lu_impl_t),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while (l != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(l->l_common->l_from_transports, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling msg_shutdown, (void *)&s);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x Sent %d shutdown requests for %s\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while (c != NULL) {
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 "SAM%x FastFree %d ... "
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "Waiting for %d cmds to drain\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x Commands drained\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_cmd_create -- creates a command pointer
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 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 if ((cmd = umem_cache_alloc(t10_cmd_cache, UMEM_DEFAULT)) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t10_find_lun((t10_targ_impl_t *)t, lun_number, cmd) == False)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
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 * | t10_send_cmd -- send the given command to appropriate LUN emulation
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/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_send(t10_targ_handle_t t, t10_cmd_t *cmd, char *opt_data,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_data(t10_targ_handle_t t, t10_cmd_t *cmd, size_t offset, char *data,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * t10_cmd_state_machine -- State machine for T10 commands
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 * The state transition table is as follows:
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 * 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 * -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 Lingt10_cmd_state_machine(t10_cmd_t *c, t10_cmd_event_t e)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /* ---- Callers must already hold the mutex ---- */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling assert(pthread_mutex_trylock(&lu->l_cmd_mutex) != 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (c->c_state) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(c->c_lu->l_common->l_from_transports,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling 0, msg_cmd_send, (void *)c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling c->c_msg, (void *)c);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM: Illegal event %s on %llx\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(lu->l_common->l_from_transports, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson "Illegal event %s -- %llx\n", event_to_str(e),
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (e) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling return (c->c_state);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_cmd_shoot_event(t10_cmd_t *c, t10_cmd_event_t e)
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 * 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.
44ecc5327ab4ce0750dcca2a17e05566bf2812e2George Wilson (void) pthread_mutex_unlock(&lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_task_mgmt -- handle SAM-3 task management needs
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_task_mgmt(t10_targ_handle_t t1, TaskOp_t op, int opt_lun, void *tag)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*CSTYLED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } while ((lu = AVL_NEXT(&t->s_open_lu, lu)) != NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*CSTYLED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling } while ((lu = AVL_NEXT(&t->s_open_lu, lu)) != NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((lu = avl_find(&t->s_open_lu, (void *)&search, NULL)) !=
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((lu = avl_find(&t->s_open_lu, (void *)&search, NULL)) !=
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_targ_stat -- Return stats on each LU associated with target.
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 (void) snprintf(lb, sizeof (lb), "%d", itl->l_common->l_num);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%lld", itl->l_cmds_read);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%lld", itl->l_cmds_write);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%lld", itl->l_sects_read);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(lb, sizeof (lb), "%lld", itl->l_sects_write);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_thick_provision -- fill the backing store with real blocks
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 Lingt10_thick_provision(char *target, int lun, target_queue_t *q)
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 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",
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 * 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 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 } 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 if (fallocate(cmd->c_lu->l_common->l_fd, cmd->c_lu->l_common->l_size) ==
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The lu_runner will use this buffer to copy data.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while ((offset < cmd->c_lu->l_common->l_size) && (rq == NULL)) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /*CSTYLED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(cmd->c_lu->l_common->l_from_transports, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (m->msg_type) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * An error occurred during
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * initialization which mean we
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * need to remove this target.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "STE%x received data "
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "---- Thick provo got shutdown\n");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling continue; /* don't use break */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_prt(mgmtq, Q_STE_NONIO, "STE%x fallocate worked\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * A forced shutdown is still considered a successful completion.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * Write errors and malloc failures constitute a failure.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /* ---- Completed successfully ---- */
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 target_basedir, cmd->c_lu->l_targ->s_targ_base, PARAMBASE,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((n1 = tgt_node_find(cmd->c_lu->l_common->l_root,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_dump2file(cmd->c_lu->l_common->l_root, path) ==
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(cmd->c_lu->l_common->l_from_transports, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (t != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | Methods called by emulation modules to interface with SAM-3 |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * trans_cmd_dup -- Duplicate a T10 command buffer
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 * (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 * 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
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens if ((c = umem_cache_alloc(t10_cmd_cache, UMEM_DEFAULT)) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((c->c_cdb = (uint8_t *)malloc(c->c_cdb_len)) == NULL) {
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex);
6e0cbcaa0c6f2bc34634a4cc17b099f9ecef03d1Matthew Ahrens (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | trans_send_datain -- send data to transport
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | (1) offset is only valid when a transport has set max_out to a non-zero
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 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 "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 * | trans_rqst_dataout -- Request data from transport for command
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 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 * 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 "SAM%x LUN%d DataOut rqst w/ immed, data_len 0x%x\n",
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 * The data is already in the command buffer so
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * we need to copy it out.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * It's expected since the transport allocated
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * the space, this routine will free the memory
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (*cmd->c_lu->l_data)(cmd, emul_id, offset, data, max_xfer);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LUN%d DataOut Rqst data_len 0x%x\n",
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 (*cmd->c_lu->l_data)(cmd, emul_id, offset, data, max_xfer);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | trans_send_complete -- notify transport command has finished.
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 * | 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 * | 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 (void) pthread_mutex_lock(&cmd->c_lu->l_cmd_mutex);
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 (void) pthread_mutex_unlock(&cmd->c_lu->l_cmd_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LUN%d key_sense=0x%x, "
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "ASC=0x%x, ASCQ=0x%x\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x LUN%d key_sense=0x%x\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_aiowrite(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (aiowrite(cmd->c_lu->l_common->l_fd, data, data_len, offset, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingtrans_aioread(t10_cmd_t *cmd, char *data, size_t data_len, off_t offset,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (aioread(cmd->c_lu->l_common->l_fd, data, data_len, offset, 0,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | trans_params_area -- return dtype params using a command pointer
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 return (p);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | Support routines for Routing and Task Management |
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * []------------------------------------------------------------------[]
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | t10_find_lun -- Locate a per target LUN structure
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/*ARGSUSED*/
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_find_lun(t10_targ_impl_t *t, int lun, t10_cmd_t *cmd)
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 if ((l = avl_find(&t->s_open_lu, (void *)&search, &wt)) != NULL) {
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.
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens * First access for this I_T_L so we need to allocate space for it.
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
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 (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),
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden while ((targ = tgt_node_next(targets_config, XML_ELEMENT_TARG, targ))
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden if ((tgt_find_value_str(targ, XML_ELEMENT_INAME, &str) ==
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden True) && (strcmp(str, t->s_targ_base) == 0)) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens } else if (str) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((ll = tgt_node_next(targ, XML_ELEMENT_LUNLIST, NULL)) == NULL)
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while ((n = tgt_node_next(ll, XML_ELEMENT_LUN, n)) != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (n == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling /* ---- ACCESS DENIED - INVALID LU IDENTIFIER ---- */
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_find_value_str(n, XML_ELEMENT_GUID, &guid) == False) {
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 * 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.
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_ILLEGAL_REQUEST, 0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens /* ---- ACCESS DENIED - INVALID LU IDENTIFIER ---- */
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((r = (xmlTextReaderPtr)xmlReaderForFd(xml_fd, NULL, NULL,
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden (void) pthread_mutex_unlock(&lu_list_mutex);
ad135b5d644628e791c3188a6ecbd9c257961ef8Christopher Siden spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
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.
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);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((strcmp(guid, "0") == 0) || (strcmp(guid, "0x0") == 0)) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if ((n1 = tgt_node_find(n, XML_ELEMENT_GUID)) == NULL) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens if (tgt_update_value_str(n1, XML_ELEMENT_GUID, guid) == False) {
cde58dbc6a23d4d38db7c8866312be83221c765fMatthew Ahrens spc_sense_create(cmd, KEY_HARDWARE_ERROR, 0);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((zfsh = zfs_open(zh, dataset, ZFS_TYPE_ANY)) ==
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if (tgt_xml_decode(guid, &lc.l_guid, &lc.l_guid_len) == False) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * See if the common LUN for this GUID already exists.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((common = avl_find(&lu_list, (void *)&lc, &wc)) == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * The GUID wasn't found, so create a new LUN structure
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * and thread.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling if ((common = calloc(1, sizeof (*common))) == NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_init(&common->l_common_mutex, NULL);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) snprintf(path, sizeof (path), "%s/%s", target_basedir,
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling "SAM%x FAILED to initialize LU %d\n",
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_create(&common->l_thr_id, NULL, lu_runner,
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 * 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 * 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 (void) pthread_mutex_lock(&common->l_common_mutex);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) avl_find(&common->l_all_open, (void *)l, &wc);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling (void) pthread_mutex_unlock(&common->l_common_mutex);
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 * The common LU thread is responsible for filling in the command
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * functions and table.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling queue_message_set(common->l_from_transports, 0, msg_lu_add, (void *)l);
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingt10_lu_initialize(t10_lu_common_t *lu, char *basedir)
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 * | lu_runner -- The workhorse for each LU
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling * | This routine is the guts of the Task Router and Task Set for SAM-3.
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Lingstatic void *
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling util_title(mgmtq, Q_STE_NONIO, lu->l_internal_num, "Start LU");
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling while ((m = queue_message_get(lu->l_from_transports)) != NULL) {
3f9d6ad73e45c6823b409f93b0c8d4f62861d2d5Lin Ling switch (m->msg_type) {
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.
case msg_cmd_data_out:
case msg_lu_aio_done:
case msg_lu_add:
case msg_reset_lu:
case msg_shutdown:
NULL);
errno);
(void) pthread_mutex_unlock(
case msg_thick_provo:
provo_err = 0;
case msg_lu_capacity_change:
case msg_lu_online:
return (NULL);
char *fa;
assert(0);
assert(0);
#ifdef NDEBUG
assert(0);
#ifdef NDEBUG
assert(0);
#ifdef NDEBUG
pthread_exit((void *)0);
static Boolean_t
t10_cmd_t *c;
switch (m->msg_type) {
case msg_cmd_send:
case msg_cmd_data_out:
return (True);
return (False);
static Boolean_t
char *str;
goto error;
goto error;
False)) {
goto error;
return (True);
goto error;
goto error;
#ifndef _LP64
goto error;
return (True);
return (False);
if (lu) {
c->c_data = 0;
c->c_data_len = 0;
if (c->c_cdb) {
if (c->c_cmd_sense) {
static Boolean_t
#ifdef FALLOCATE_SUPPORTED
return (False);
return (True);
return (False);
return (True);
return (False);
static Boolean_t
assert(0);
return (False);
assert(0);
#ifdef FULL_DEBUG
assert(0);
assert(0);
assert(0);
{ 0, 0, 0, 0, 0, NULL }