www.pudn.com > SMSC USB2.0.zip > lun.c
/*============================================================================
____________________________________________________________________________
______________________________________________
SSSS M M CCCC Standard Microsystems Corporation
S MM MM SSSS C Austin Design Center
SSS M M M S C 11000 N. Mopac Expressway
S M M SSS C Stonelake Bldg. 6, Suite 500
SSSS M M S CCCC Austin, Texas 78759
SSSS ______________________________________________
____________________________________________________________________________
Copyright(C) 1999, Standard Microsystems Corporation
All Rights Reserved.
This program code listing is proprietary to SMSC and may not be copied,
distributed, or used without a license to do so. Such license may have
Limited or Restricted Rights. Please refer to the license for further
clarification.
____________________________________________________________________________
Notice: The program contained in this listing is a proprietary trade
secret of SMSC, Hauppauge, New York, and is copyrighted
under the United States Copyright Act of 1976 as an unpublished work,
pursuant to Section 104 and Section 408 of Title XVII of the United
States code. Unauthorized copying, adaption, distribution, use, or
display is prohibited by this law.
____________________________________________________________________________
Use, duplication, or disclosure by the Government is subject to
restrictions as set forth in subparagraph(c)(1)(ii) of the Rights
in Technical Data and Computer Software clause at DFARS 52.227-7013.
Contractor/Manufacturer is Standard Microsystems Corporation,
80 Arkay Drive, Hauppauge, New York, 1178-8847.
____________________________________________________________________________
____________________________________________________________________________
-
____________________________________________________________________________
comments tbd
____________________________________________________________________________
Revision History
Date Who Comment
________ ___ _____________________________________________________________
04/20/01 cds initial version
11/27/01 cds - added lun_enable_mux() stub
- converted all methods to reentrant model
12/06/01 tbh clean sweep re-organization
01/15/02 cds - added base start-stop unit command for all removable
media luns.
- added read format capacity processing for all luns
- added function comment stubs (in off chance we have time
to comment functions that we won't have to rip out later)
02/26/02 tbh added logical to physical lun mapping, absorbed lun tables etc
moved in here from project.h
04/08/02 tbh - on start/stop-eject - if card was mmc then map sd back into
the logical lun.
04/17/02 tbh added k_protocol_mode_sense_6 case to lun_process_cdb to
allow MS (and SM) to override the mode_sense dfa so as to
report the WP bit to prevent write commands to rom only cards.
04/18/02 tbh replaced dfa_lun_mode_sense with minimal version required
to report write protect bit based on lun data.
04/29/02 tbh based on Sashi's analysis of the sense codes we report
i updated them as follows:
- illegal_opcode/05/20/00 for unsupported commands
- illegal_cmdpkt/05/24/00 for supported command but unsupported option
- illegal_rqst/05/26/xx for command parameter error from host
06/05/02 cds updated inquiry function to check media flags before setting/clearing
removable media bit
06/10/02 tbh performance optimizations by adding __thread_return_dfa()
to trick dfa_lun_read and dfa_lun_write into running and
exiting correctly when called as functions instead of dfa's
06/21/02 cds added nand lun to the vtbl table, and removed the _vtbl(nil)
class since it is not necessary. _vtbl(lun) has been replaced
by a simple _vtbl(lun) with all methods set to NULL, instead
of a vtbl initialized with methods that may not have implementations.
06/28/02 ds Added support for Mode_Sense 10 command.
07/01/02 tbh handle write protect at the lun layer.
(later fixed typo that set MS to wrprot instead of g_active_lun)
07/09/02 cds moved definition of g_sector_buffer here for use by all luns
07/11/02 tbh altered dfa_lun_inquiry to stuff an ascii version of the vid/pid
as extracted from nvstore into the vendorinfo field of the inquiry
data to allow the smsc WinXX custom icon application to enumerate
the drives and discover our vid/pid (w/out knowing if its a usb
drive or not) and match the vid/pid with an inf file.
07/12/02 tbh altered dfa_lun_inquiry again to follow then new scheme for
stuffing the vendor/product strings for custom icon matching.
07/23/02 tbh modified dfa_lun_start_stop_unit to handle eject differently.
because of recent requirement for "card present" leds, and SD
card insert/eject crippled hardware, the SD card must be periodically
probed to see if tis loaded (because W2K etc won;t send periodic TURs
to probe the card). so, on an eject, changed the command handler
to no longer clear the sd/mmc present bits in x_crd_ps register.
this prevents the SD prober from firing, avoiding the annoying
return of the icon under XP and OSX (which do send periodic TUR).
08/01/02 ds On a software eject the SD LED was not getting turned off. Fixed that.
08/01/02 tbh rollback last change. bug report was incorrect.
08/13/02 tbh there was a bug in dfa_lun)inquiry in that nvstore_read() will
return garbage if the nvstore hasn't been written yet.
08/20/02 cds added some lun trace points to track down sm/nand/ms corruption
09/05/02 tbh removed dead broken code
09/10/02 tbh inserted non-space default values for vendor and product
strings in the inquiry response template.
09/11/02 tbh modified so shorter strings in the nvstore will overwrite
the longer default strings in dfa_lun_inquiry.
09/19/02 cds added second 'default' mode sense function which can be used for
sm, nand, or memory stick luns (or any lun using the log2phy mapper)
to relay media geometry to host.
09/21/02 tbh added lun_process_idle()
09/22/02 tbh eliminated unused code on 242 builds
09/22/02 tbh pad the vendor name with spaces in inquiry data
09/23/02 tbh added an else to the padding code to make it work properly
09/23/02 cds moved mode sense dfa for fmt dev page from lun.c to media.c so that
luns w/o the mapper will be able to link
09/25/02 cds added support for erase_flash and report_media_geometry lun dfas
09/26/02 cds updated small data xfers to use a central function to tx a buffer
instead of repeated the tx code all over.
10/01/02 cds converted _lun_is_media_XXX() macros to functions to conserve
code space.
10/01/02 ds Added implementation for dfa_lun_secure_memory_read and dfa_lun_secure_memory_write
to support two vendor specific commands to write to a 24byte secure area in the nvstore.
10/02/02 jwc Changed descriptors to always report HS to workaround WHQL bug reported by TW.
g_sector_buffer[off++] = (_mcu_register_rd(x_sie_conf) & kbm_sie_conf_hspeed) ? 'H' : 'H';
10/02/02 ds Added code to trap a timeout error on receiving the data packet in dfa_lun_secure_memory_write
10/02/02 ds Added code to verify after a nvstore-write is done.
10/03/02 ds Fixed Bug ID 359: The functions _lun_is_media_known and _lun_is_media_present are being
called from the high priority BOT layer.So, they must be protected by #pragma NOAREGS
10/07/02 ds -Modified dfa_lun_inquiry to fetch the Vendor ID (8 bytes) and Product ID Header (5 bytes)
from the nvstore, instead of the mfg and prd strings.
-Made all lun_media_xxx functions protectes by #pragma NOAREGS
10/10/02 cds - added new call "lun_is_media_ready()" to allow lun to check whether or not a read/write
cb can be issued.
10/11/02 cds added vendor commands cf-10, cf-11 to be executed regardless of unhappy sense
10/15/02 cds updated inquiry to simply copy inq_vid and inq_pid_hdr from xdata buffer instead of building them at run-time
10/17/02 cds - project-wide lun data & vtbl paging to reduce code space.
- removed g_active_media from _lun_data, _lun_() virtual functions
- added _lun_data_rd() and _lun_data_wr() macros to bypass lun paging
- added lun_set_active(log_lun) function to switch luns
============================================================================*/
#define __lun_dot_c__
#include "project.h"
#include "dev.h"
//------------------------------------------------------------------------------
// _vtbl_defn(lun) is not a valid class... it is akin to a "pure virtual" or interface class,
// and as such should not have a stand-alone vtble defined under our
// implementation.
//
// Since we need a "placeholder" vtbl for log-to-phy lun mapping (dynamic
// sub-classing), but cannot have a non-subclassed 'lun', we can eliminated
// either _vtbl_defn(lun) or _vtbl_defn(nil). I opted to axe the _vtbl(nil)
// provide vtable definition '_vtbl_lun'
code _vtbl_decl(lun) = { (t_thd_entry) NULL} ;
//------------------------------------------------------------------------------
// tables indexed by physical lun number. they are fixed, and do not change orded with build
xdata t_lun_data g_lun_data[k_max_phy_lun];
code t_thd_entry* g_lun_tbl[k_max_phy_lun] =
{
#if (k_log_lun_cf < k_max_log_lun)
_vtbl(cf),
#else
_vtbl(lun),
#endif
#if (k_log_lun_ms < k_max_log_lun)
_vtbl(ms),
#else
_vtbl(lun),
#endif
#if (k_log_lun_sm < k_max_log_lun)
_vtbl(sm),
#else
_vtbl(lun),
#endif
#if (k_log_lun_sd < k_max_log_lun)
_vtbl(sd),
#else
_vtbl(lun),
#endif
#if (k_log_lun_mmc < k_max_log_lun)
_vtbl(mmc),
#else
_vtbl(lun),
#endif
#if (k_log_lun_nand < k_max_log_lun)
_vtbl(nand)
#else
_vtbl(lun)
#endif
};
//------------------------------------------------------------------------------
// this is a physical lun
xdata uint8 g_active_lun;
// indexed by logical lun
xdata uint8 g_lun_log2phy_map[k_max_log_lun];
// sector buffer used by luns to store temporary sector data
xdata uint8 g_sector_buffer[k_sector_sz] ;
// prototypes
uint8 nvstore_read(uint8 addr) reentrant;
void nvstore_write(uint8 addr, uint8 value) reentrant;
void nvstore_write_enable(void) reentrant;
void nvstore_write_disable(void) reentrant;
// _lun_is_media_XXX() style functions acting as macros
//DS WARNING!!! THESE FUNCTIONS SHOULD BE PROTECTED BY #PRAGMA NOAREGS, IF THEY ARE CALLED FROM
//INTERRUPT LEVEL CODE (HIGH PRIORITY)
#pragma NOAREGS
//+-----------------------------------------------------------------------------
t_bool _lun_is_media_present(uint8 lun) reentrant
{
return(__lun_is_media_present(lun));
}
//+-----------------------------------------------------------------------------
t_bool _lun_is_media_known(uint8 lun) reentrant
{
return(__lun_is_media_known(lun));
}
//+-----------------------------------------------------------------------------
t_bool _lun_is_media_changed(uint8 lun) reentrant
{
return(__lun_is_media_changed(lun));
}
//+-----------------------------------------------------------------------------
t_bool _lun_is_media_lockable(uint8 lun) reentrant
{
return(__lun_is_media_lockable(lun));
}
//+-----------------------------------------------------------------------------
t_bool _lun_is_media_removable(uint8 lun) reentrant
{
return(__lun_is_media_removable(lun));
}
//+-----------------------------------------------------------------------------
t_bool _lun_requests_idle_processing(uint8 lun) reentrant
{
return(__lun_requests_idle_processing(lun));
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
t_bool lun_is_media_ready() reentrant
{
uint8 media;
media = _lun_data(media);
#ifdef k_opt_password
if (!(_lun_is_media_present(g_active_lun)))
{
trace0(0, dev, 0, "Moving on to process cb");
return k_false;
}
#else
if (!(media & kbm_lun_media_present))
return k_false;
#endif
if (media & kbm_lun_media_changed)
return k_false;
if (media & kbm_lun_media_unknown)
return k_false;
return k_true;
}
#pragma AREGS
//------------------------------------------------------------------------------
// active lun 'page'
xdata t_sense code *g_lun_data_sensep ; // the sense code to report on next request sense
xdata t_sense code *g_lun_data_statusp ; // the current, volatile status of the device
xdata uint8 g_lun_data_sense_data[3]; // additional sense data
xdata uint8 g_lun_data_device_id[k_lun_max_devid_sz]; // inquiry and device identification data
xdata uint8 g_lun_data_media ;
xdata t_capacity g_lun_data_capacity ; // capacity (and fmt capacity) of current media
xdata uint32 g_lun_data_max_lb_per_split;
xdata uint32 g_lun_data_max_lb_per_burst;
xdata uint8 g_lun_data_device_type; // set in dfa_initialize
//------------------------------------------------------------------------------
// active lun 'vtbl'
xdata t_thd_entry v_lun_process_idle;
xdata t_thd_entry v_lun_enable_mux;
xdata t_thd_entry v_lun_reset_controller;
xdata t_thd_entry v_lun_initialize_controller;
xdata t_thd_entry v_dfa_lun_reset_media;
xdata t_thd_entry v_dfa_lun_initialize_media;
xdata t_thd_entry v_dfa_lun_identify_media;
xdata t_thd_entry v_dfa_lun_inquiry;
xdata t_thd_entry v_dfa_lun_test_unit_ready;
xdata t_thd_entry v_dfa_lun_req_sense;
xdata t_thd_entry v_dfa_lun_read_capacity;
xdata t_thd_entry v_dfa_lun_read;
xdata t_thd_entry v_dfa_lun_write;
xdata t_thd_entry v_dfa_lun_verify;
xdata t_thd_entry v_dfa_lun_mode_sense;
xdata t_thd_entry v_dfa_lun_mode_select;
xdata t_thd_entry v_dfa_lun_read_format_capacity;
xdata t_thd_entry v_dfa_lun_format_unit;
xdata t_thd_entry v_dfa_lun_start_stop_unit;
xdata t_thd_entry v_dfa_lun_prevent_allow_access;
xdata t_thd_entry v_dfa_lun_sync_cache;
xdata t_thd_entry v_dfa_lun_device_diagnostics;
xdata t_thd_entry v_dfa_lun_erase_media;
xdata t_thd_entry v_dfa_lun_report_media_geometry;
xdata t_thd_entry v_dfa_lun_secure_memory_read;
xdata t_thd_entry v_dfa_lun_secure_memory_write;
xdata t_thd_entry v_dfa_lun_process_cb;
#pragma NOAREGS
#if 0
void lun_trace_vtbl() reentrant
{
TRACE1(47, lun, 0, "v_lun_process_idle: %04x", (uint16)v_lun_process_idle);
TRACE1(48, lun, 0, "v_lun_enable_mux: %04x", (uint16) v_lun_enable_mux);
TRACE1(49, lun, 0, "v_lun_reset_controller: %04x", (uint16) v_lun_reset_controller);
TRACE1(50, lun, 0, "v_lun_initialize_controller: %04x", (uint16) v_lun_initialize_controller);
TRACE1(51, lun, 0, "v_dfa_lun_reset_media: %04x", (uint16) v_dfa_lun_reset_media);
TRACE1(52, lun, 0, "v_dfa_lun_initialize_media: %04x", (uint16) v_dfa_lun_initialize_media);
TRACE1(53, lun, 0, "v_dfa_lun_identify_media: %04x", (uint16) v_dfa_lun_identify_media);
TRACE1(54, lun, 0, "v_dfa_lun_inquiry: %04x", (uint16) v_dfa_lun_inquiry);
TRACE1(55, lun, 0, "v_dfa_lun_test_unit_ready: %04x", (uint16) v_dfa_lun_test_unit_ready);
TRACE1(56, lun, 0, "v_dfa_lun_req_sense: %04x", (uint16) v_dfa_lun_req_sense);
TRACE1(57, lun, 0, "v_dfa_lun_read_capacity: %04x", (uint16) v_dfa_lun_read_capacity);
TRACE1(58, lun, 0, "v_dfa_lun_read: %04x", (uint16) v_dfa_lun_read);
TRACE1(59, lun, 0, "v_dfa_lun_write: %04x", (uint16) v_dfa_lun_write);
TRACE1(60, lun, 0, "v_dfa_lun_verify: %04x", (uint16) v_dfa_lun_verify);
TRACE1(61, lun, 0, "v_dfa_lun_mode_sense: %04x", (uint16) v_dfa_lun_mode_sense);
TRACE1(62, lun, 0, "v_dfa_lun_mode_select: %04x", (uint16) v_dfa_lun_mode_select);
TRACE1(63, lun, 0, "v_dfa_lun_read_format_capacity: %04x", (uint16) v_dfa_lun_read_format_capacity);
TRACE1(64, lun, 0, "v_dfa_lun_format_unit: %04x", (uint16) v_dfa_lun_secure_memory_read);
TRACE1(65, lun, 0, "v_dfa_lun_start_stop_unit: %04x", (uint16) v_dfa_lun_start_stop_unit);
TRACE1(66, lun, 0, "v_dfa_lun_prevent_allow_access: %04x", (uint16) v_dfa_lun_prevent_allow_access);
TRACE1(67, lun, 0, "v_dfa_lun_sync_cache: %04x", (uint16) v_dfa_lun_sync_cache);
TRACE1(68, lun, 0, "v_dfa_lun_device_diagnostics: %04x", (uint16) v_dfa_lun_device_diagnostics);
TRACE1(69, lun, 0, "v_dfa_lun_erase_media: %04x", (uint16) v_dfa_lun_erase_media);
TRACE1(70, lun, 0, "v_dfa_lun_report_media_geometry: %04x", (uint16) v_dfa_lun_report_media_geometry);
TRACE1(71, lun, 0, "v_dfa_lun_secure_memory_read: %04x", (uint16) v_dfa_lun_secure_memory_read);
TRACE1(72, lun, 0, "v_dfa_lun_secure_memory_write: %04x", (uint16) v_dfa_lun_secure_memory_write);
TRACE1(73, lun, 0, "v_dfa_lun_process_cb: %04x", (uint16) v_dfa_lun_process_cb);
}
#endif
//+-----------------------------------------------------------------------------
// Name:
// media_set_active()
//
// Declaration:
// void media_set_active(uint8 media) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void lun_set_active(uint8 lun) reentrant
{
mcu_begin_critical_section() ;
if(g_active_lun != lun)
{
if (g_active_lunsense_key, psense->additional_sense_code, psense->asc_qualifier );
if (&sense_none == psense)
{
TRACE0(79, lun, 99, "sense_none");
}
/*
if (&sense_bad_lun == psense)
{
TRACE0(80, lun, 99, "sense_bad_lun");
}
*/
if (&sense_media_change == psense)
{
TRACE0(81, lun, 99, "sense_media_change");
}
if (&sense_no_media == psense)
{
TRACE0(82, lun, 99, "sense_no_media");
}
/*
if (&sense_becoming_ready == psense)
{
TRACE0(83, lun, 99, "sense_becoming_ready");
}
*/
if (&sense_read_error == psense)
{
TRACE0(84, lun, 99, "sense_read_error");
}
/*
if (&sense_fmt_failed == psense)
{
TRACE0(85, lun, 99, "sense_fmt_failed");
}
if (&sense_no_seek == psense)
{
TRACE0(86, lun, 99, "sense_no_seek");
}
*/
if (&sense_por == psense)
{
TRACE0(87, lun, 99, "sense_por");
}
if (&sense_illegal_request == psense)
{
TRACE0(88, lun, 99, "sense_illegal_request");
}
if (&sense_write_error == psense)
{
TRACE0(89, lun, 99, "sense_write_error");
}
/*
if (&sense_no_fmt == psense)
{
TRACE0(90, lun, 99, "sense_no_fmt");
}
*/
if (&sense_write_protect == psense)
{
TRACE0(91, lun, 99, "sense_write_protect");
}
/*
if (&sense_write_protect_hw == psense)
{
TRACE0(92, lun, 99, "sense_write_protect_hw");
}
if (&sense_write_protect_sw_lun == psense)
{
TRACE0(93, lun, 99, "sense_write_protect_sw_lun");
}
if (&sense_write_protect_assoc == psense)
{
TRACE0(94, lun, 99, "sense_write_protect_assoc");
}
if (&sense_write_protect_persist == psense)
{
TRACE0(95, lun, 99, "sense_write_protect_persist");
}
if (&sense_write_protect_perm == psense)
{
TRACE0(96, lun, 99, "sense_write_protect_perm");
}
*/
if (&sense_illegal_cmdpkt == psense)
{
TRACE0(97, lun, 99, "sense_illegal_cmdpkt");
}
/*
if (&sense_saving_not_support == psense)
{
TRACE0(98, lun, 99, "sense_saving_not_support");
}
*/
if (&sense_illegal_length == psense)
{
TRACE0(99, lun, 99, "sense_illegal_length");
}
if (&sense_illegal_address == psense)
{
TRACE0(100, lun, 99, "sense_illegal_address");
}
if (&sense_illegal_opcode == psense)
{
TRACE0(101, lun, 99, "sense_illegal_opcode");
}
mcu_end_critical_section() ;
}
#endif
//+-----------------------------------------------------------------------------
// Name:
// lun_process_idle
//
// Declaration:
// void lun_process_idle(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// This is a FUNCTION, NOT a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void lun_process_idle(void) reentrant
{
TRACE0(102, lun, 0, "lun_process_idle() - error: pure virtual function must be overridden");
}
//+-----------------------------------------------------------------------------
// Name:
// lun_enable_mux
//
// Declaration:
// void lun_enable_mux(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// This is a FUNCTION, NOT a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void lun_enable_mux(void) reentrant
{
TRACE0(103, lun, 0, "lun_enable_mux() - error: pure virtual function must be overridden");
}
//+-----------------------------------------------------------------------------
// Name:
// lun_reset_controller
//
// Declaration:
// void lun_reset_controller(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// This is a FUNCTION, NOT a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void lun_reset_controller(void) reentrant
{
TRACE0(104, lun, 0, "lun_reset_controller() - warning: pure virtual function should be overridden");
}
//+-----------------------------------------------------------------------------
// Name:
// lun_initialize_controller
//
// Declaration:
// void lun_initialize_controller(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// This is a FUNCTION, NOT a DFA.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void lun_initialize_controller(void) reentrant
{
TRACE0(105, lun, 0, "lun_initialize_controller() - warning: pure virtual function should be overridden");
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_reset_media
//
// Declaration:
// void dfa_lun_reset_media(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should be overridden. Derived method should set callbacks, then call this.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_reset_media(void) reentrant
{
TRACE0(106, lun, 0, "dfa_lun_reset_media() - error: pure virtual method must be overridden");
_thread_return_dfa(k_error);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_initialize_media
//
// Declaration:
// void dfa_lun_initialize_media(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should be overridden. Derived method should set callbacks, then call this.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_initialize_media(void) reentrant
{
TRACE0(107, lun, 0, "dfa_lun_initialize_media() - error: pure virtual method must be overridden");
_thread_return_dfa(k_error);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_identify_media
//
// Declaration:
// void dfa_lun_identify_media(void);
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should be overridden. Derived method should set callbacks, then call this.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_identify_media(void) reentrant
{
TRACE0(108, lun, 0, "dfa_lun_identify_media() - error: pure virtual method must be overridden");
_thread_return_dfa(k_error);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_test_unit_ready
//
// Declaration:
// void dfa_lun_test_unit_ready(void);
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// Should be overridden. Derived method should set callbacks, then call this.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_test_unit_ready(void)reentrant
{
trace0(0, msc, 0, "dfa_lun_test_unit_ready()");
_thread_return_dfa((_lun_data(sensep) == &sense_none) ? k_command_passed : k_command_failed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_req_sense
//
// Declaration:
// void dfa_lun_req_sense(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_req_sense(void)reentrant
{
uint8 length;
length = _min(sizeof(t_sense), g_bot_cbw.cdb[4]);
mscbot_tx_data_buffer((uint8*) _lun_data(sensep), length);
TRACE0(109, lun, 0, "reporting:");
lun_dump_sense(g_active_lun);
_lun_data(sensep) = &sense_none;
_thread_return_dfa(k_command_passed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_read_capacity()
//
// Declaration:
// void dfa_lun_read_capacity(void) reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_read_capacity(void)reentrant
{
uint8* ptr;
uint8 i;
TRACE0(110, lun, 0, "dfa_lun_read_capacity()");
lun_dump_sense(g_active_lun);
g_tmp = _lun_data(media);
// check for no media
if (!(g_tmp & kbm_lun_media_present))
{
TRACE0(111, lun, 0, "no media present... setting command failed") ;
_lun_data(sensep) = &sense_no_media;
_thread_return_dfa(k_command_failed);
}
// check for media changed
if (g_tmp & kbm_lun_media_unknown)
{
TRACE0(112, lun, 0, "media unknown... setting media change sense") ;
_lun_data(sensep) = &sense_media_change;
_thread_return_dfa(k_command_failed);
}
// validate command parameters
//reladr = (g_bot_cbw.cdb[1] & 0x01);
//lba = _uint32(g_bot_cbw.cdb[2], g_bot_cbw.cdb[3], g_bot_cbw.cdb[4], g_bot_cbw.cdb[5]);
//pmi = (g_bot_cbw.cdb[8] & 0x01);
//if (!reladr || !pmi || lba)
//{
// _lun_data(g_active_lun, sensep) = &sense_illegal_rqst;
//}
// check for any error
if (_lun_data(sensep) != &sense_none)
{
TRACE0(113, lun, 0, "active lun sensep != sense_none. failing command") ;
lun_dump_sense(g_active_lun);
_thread_return_dfa(k_command_failed);
}
// report the data to the host
stream_open(2, k_data_in);
ptr = (uint8*) &(_lun_data(capacity));
//lba = _lun_data(g_active_lun, capacity).lba_max.u32 - 1;
for (i=0; i<8; i++)
{
while (!stream_put(2, ptr[i]));
}
_mscbot_zero_residue();
stream_close(2);
_lun_data(sensep) = &sense_none;
_thread_return_dfa(k_command_passed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_read
//
// Declaration:
// void dfa_lun_read(void);
//
// Purpose:
// Read data from an ata drive.
//
// Arguments:
// None.
// Uses _lun_data and g_bot_cbw to get its parameters.
//
// Return:
// No return value.
// However, on exit the DFA's argument pointer is written with a t_csw_status indicating:
// k_command_passed - command completed.
// k_command_failed - an error occurred.
//
// Notes:
// Should be overridden. Derived method should set callbacks, then call this.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
// BBB: the first optimization to this was to call it directly from dfa_lun_process_cb.
// that eliminated a dfa layer (55usec push, 66usec pop) and required no changes here.
// the second optimization was to call it directly from dev_thread_wait_cbw.
// that eliminated another dfa layer cutting out 240 to 270 usec in toto (as measured)
// but required a change here. all of the _thread_return_dfa() calls had to be replaced
// with __thread_return_dfa() calls to eliminate the final call to thread_end_dfa()
// (because its not run as a dfa any more, it just looks very much like one due to
// mildly clever macroitization) and replace it with a simple return.
// 07/01/02 - tbh - moved to lun.h
//#define __thread_return_dfa(__val) { (*(uint8 *)thread_rd_dfa_argp())=(__val); return; }
void dfa_lun_read(void)reentrant
{
// profile: ~46..49 usec
#if 0
TRACE0(114, lun, 0, "dfa_lun_read() - error: pure virtual method must be overridden");
_lun_data(sensep) = &sense_illegal_opcode;
__thread_return_dfa(k_command_failed);
#else
//_profile_on(7);
TRACE0(115, fmc, 0, "dfa_lun_read()");
if (_lun_data(sensep) != &sense_none)
{
TRACE1(116, fmc, 0, "sensep: %04x", ((uint16) _lun_data(sensep))); // use lun_dump_sense()
__thread_return_dfa(k_command_failed);
}
_fmc_set_start_lb_8(g_bot_cbw.cdb[2], g_bot_cbw.cdb[3], g_bot_cbw.cdb[4], g_bot_cbw.cdb[5]);
// do you trust the host enough to sacrifice robustness for speed here? are you sure?
#ifndef k_optimizeXXX
// valid lba range - required if host just wants to validate a range of addresses w/o a data xfer
if (_fmc_get_start_lb_32() > _lun_data(capacity).lba_max.u32)
{
TRACE2(117, fmc, 0, "dfa_lun_read() - error bad lba:%04X%04X", (_fmc_get_start_lb_32() >> 16), (_fmc_get_start_lb_32() & 0xffff));
_lun_data(sensep) = &sense_illegal_address;
__thread_return_dfa(k_command_failed);
}
#endif
if (g_bot_cbw.cdb[0] == k_protocol_read_10)
{
TRACE0(118, fmc, 1, "read_10 command");
_fmc_set_lb_count_8(0, 0, g_bot_cbw.cdb[7], g_bot_cbw.cdb[8]);
}
else
{
TRACE0(119, fmc, 1, "read 12 command");
_fmc_set_lb_count_8(g_bot_cbw.cdb[6], g_bot_cbw.cdb[7], g_bot_cbw.cdb[8], g_bot_cbw.cdb[9]);
}
TRACE4(120, fmc, 0, "read lba:%04X%04X xfer_length:%04X%04X", _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), _hw(g_n_lb_this_xfer.u32), _lw(g_n_lb_this_xfer.u32));
// do you trust the host enough to sacrifice robustness for speed here? are you sure?
#ifndef k_optimizeXXX
if ((_fmc_get_start_lb_32() + _fmc_get_lb_count_32() - 1L) > _lun_data(capacity).lba_max.u32)
{
TRACE0(121, fmc, 0, "dfa_lun_read() - lba range invalid\n");
TRACE2(122, fmc, 0, "dfa_lun_read() - error bad start:%04X%04X", (_fmc_get_start_lb_32() >> 16), (_fmc_get_start_lb_32() & 0xffff));
TRACE2(123, fmc, 0, "dfa_lun_read() - error bad count:%04X%04X", (_fmc_get_lb_count_32() >> 16), (_fmc_get_lb_count_32() & 0xffff));
TRACE2(124, fmc, 0, "dfa_lun_read() - capacity:%04X%04X", (_lun_data(capacity).lba_max.u32 >> 16), (_lun_data(capacity).lba_max.u32 & 0xffff));
_lun_data(sensep) = &sense_illegal_address;
__thread_return_dfa(k_command_failed);
}
#endif
//_profile_off(7); //ABOUT 46 usec
if (k_success != fmc_transfer())
__thread_return_dfa(k_command_failed);
if (_lun_data(sensep) != &sense_none)
__thread_return_dfa(k_command_failed);
__thread_return_dfa(k_command_passed);
#endif
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_write
//
// Declaration:
// void dfa_lun_write(void);
//
// Purpose:
// Write data.
//
// Arguments:
// None.
// Uses _lun_data and g_bot_cbw to get its parameters.
//
// Return:
// No return value.
// However, on exit the DFA's argument pointer is written with a t_csw_status indicating:
// k_command_passed - command completed.
// k_command_failed - an error occurred.
//
// Notes:
// Should be overridden. Derived method should set callbacks, then call this.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
// BBB: the first optimization to this was to cal it directly from dfa_lun_process_cb.
// that eliminated a dfa layer (55usec push, 66usec pop) and required no changes here.
// the second optimization was to call it directly from dev_thread_wait_cbw.
// that eliminated another dfa layer cutting out 240 to 270 usec in toto (as measured)
// but required a change here. all of the _thread_return_dfa() calls had to be replaced
// with __thread_return_dfa() calls to eliminate the final call to thread_end_dfa()
// (because its not run as a dfa any more, it just looks very much like one due to
// mildly clever macroitization) and replace it with a simple return.
void dfa_lun_write(void)reentrant
{
#if 0
TRACE0(125, lun, 0, "dfa_lun_write() - error: pure virtual method must be overridden");
_lun_data(sensep) = &sense_illegal_opcode;
__thread_return_dfa(k_command_failed);
#else
TRACE0(126, lun, 0, "dfa_lun_write");
if (_lun_data(media) & kbm_lun_media_wrprot)
{
TRACE0(127, lun, 10, "write protected");
_lun_data(sensep) = &sense_write_protect;
__thread_return_dfa(k_command_failed);
}
if (_lun_data(sensep) != &sense_none)
{
__thread_return_dfa(k_command_failed);
}
_fmc_set_start_lb_8(g_bot_cbw.cdb[2], g_bot_cbw.cdb[3], g_bot_cbw.cdb[4], g_bot_cbw.cdb[5]);
// do you trust the host enough to sacrifice robustness for speed here? are you sure?
#ifndef k_optimizeXXX
if (_fmc_get_start_lb_32() > _lun_data(capacity).lba_max.u32)
{
TRACE2(128, fmc, 0, "dfa_lun_write() - error bad lba:%04X%04X", (_fmc_get_start_lb_32() >> 16), (_fmc_get_start_lb_32() & 0xffff));
_lun_data(sensep) = &sense_illegal_address;
__thread_return_dfa(k_command_failed);
}
#endif
if (g_bot_cbw.cdb[0] == k_protocol_write_10)
{
TRACE0(129, fmc, 1, "write 10 command");
_fmc_set_lb_count_8(0, 0, g_bot_cbw.cdb[7], g_bot_cbw.cdb[8]);
}
else
{
TRACE0(130, fmc, 1, "write 12 command");
_fmc_set_lb_count_8(g_bot_cbw.cdb[6], g_bot_cbw.cdb[7], g_bot_cbw.cdb[8], g_bot_cbw.cdb[9]);
}
TRACE4(131, fmc, 0, "write lba:%04X%04X xfer_length:%04X%04X", _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), _hw(g_n_lb_this_xfer.u32), _lw(g_n_lb_this_xfer.u32));
// do you trust the host enough to sacrifice robustness for speed here? are you sure?
#ifndef k_optimizeXXX
if ((_fmc_get_start_lb_32() + _fmc_get_lb_count_32() - 1L) > _lun_data(capacity).lba_max.u32)
{
TRACE0(132, fmc, 0, "dfa_lun_write() - lba range invalid\n");
_lun_data(sensep) = &sense_illegal_address;
__thread_return_dfa(k_command_failed);
}
#endif
if (k_success != fmc_transfer())
__thread_return_dfa(k_command_failed);
if (_lun_data(sensep) != &sense_none)
__thread_return_dfa(k_command_failed);
__thread_return_dfa(k_command_passed);
#endif
}
//------------------------------------------------------------------------------
// verify options
#define kbm_verify_options_dpo 0x04
#define kbm_verify_options_bytchk 0x02
#define kbm_verify_options_reladr 0x01
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_verify
//
// Declaration:
// void dfa_lun_verify(void);
//
// Purpose:
// Verify that the data on the drive matches the data sent down.
//
// Arguments:
// None.
// Uses _lun_data and g_bot_cbw to get its parameters.
//
// Return:
// No return value.
// However, on exit the DFA's argument pointer is written with a t_csw_status indicating:
// k_command_passed - command completed.
// k_command_failed - an error occurred.
//
// Notes:
// !!!???This implementation is incorrect. It should not write the data to the drive,
// but should read the drive and compare to the provided data???
// Should be overridden. Derived method should set callbacks, then call this.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_verify(void)reentrant
{
#if 0
TRACE0(133, lun, 0, "dfa_lun_verify() - error: pure virtual method must be overridden");
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
#else
uint8 vopt;
TRACE0(134, fmc, 0, "dfa_lun_verify");
if (_lun_data(sensep) != &sense_none)
{
_thread_return_dfa(k_command_failed);
}
vopt = g_bot_cbw.cdb[1];
_fmc_get_start_lb_8(g_bot_cbw.cdb[2], g_bot_cbw.cdb[3], g_bot_cbw.cdb[4], g_bot_cbw.cdb[5]);
// valid lba range - required if host just wants to validate a range of addresses w/o a data xfer
if (_fmc_get_start_lb_32() > _lun_data(capacity).lba_max.u32)
{
TRACE0(135, fmc, 0, "verify error: invalid lba");
_lun_data(sensep) = &sense_illegal_address;
_thread_return_dfa(k_command_failed);
}
_fmc_set_lb_count_8(0, 0, g_bot_cbw.cdb[7], g_bot_cbw.cdb[8]);
if ((_fmc_get_start_lb_32() + _fmc_get_lb_count_32() - 1L) > _lun_data(capacity).lba_max.u32)
{
TRACE0(136, fmc, 0, "verify error: lba range invalid\n");
_lun_data(sensep) = &sense_illegal_address;
_thread_return_dfa(k_command_failed);
}
// check to see if there is any data transfer
if (!(vopt & kbm_verify_options_bytchk))
{
// no data comparrison, so just return a-ok.
TRACE0(137, fmc, 0, "verify: no data comparison... just say ok\n");
_lun_data(sensep) = &sense_none;
_thread_return_dfa(k_command_passed);
}
TRACE4(138, fmc, 0, "verify lba:%04X%04X xfer_length:%04X%04X", _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), _hw(g_n_lb_this_xfer.u32), _lw(g_n_lb_this_xfer.u32));
TRACE4(139, fmc, 0, "verify - opts:0x%02X vlba:%04X%04X vlen:%04X", vopt, _hw(_fmc_get_start_lb_32()), _lw(_fmc_get_start_lb_32()), g_n_lb_this_xfer.u32);
if (k_success != fmc_transfer())
_thread_return_dfa(k_command_failed);
if (_lun_data(sensep) != &sense_none)
_thread_return_dfa(k_command_failed);
_thread_return_dfa(k_command_passed);
#endif
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_mode_sense()
//
// Declaration:
// void dfa_lun_mode_sense(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
// spc3r07 8.4 - 4 bytes of header: mode-data-length, medium-type, device-parm, block-len
uint8 code _msense[4] = { 0x03, 0x00, 0x00, 0x00};
uint8 code _msense_wp[4] = { 0x03, 0x00, 0x80, 0x00};
uint8 code _msense10[8] = { 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8 code _msense10_wp[8] = { 0x00, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00};
void dfa_lun_mode_sense(void) reentrant
{
// uint8 pnr;
uint8 cmd = g_bot_cbw.cdb[0];
TRACE0(140, lun, 0, "dfa_lun_mode_sense()");
if ( cmd == k_protocol_mode_sense_10)
{
if (_lun_data(media)&kbm_lun_media_wrprot)
{
TRACE0(141, lun, 10, "write protected");
mscbot_tx_data_buffer((uint8*) _msense10_wp, sizeof(_msense10_wp));
}
else
{
mscbot_tx_data_buffer((uint8*) _msense10, sizeof(_msense10));
}
}
else
{
if (_lun_data(media) & kbm_lun_media_wrprot)
{
TRACE0(142, lun, 10, "write protected");
mscbot_tx_data_buffer((uint8*) _msense_wp, sizeof(_msense_wp));
}
else
{
mscbot_tx_data_buffer((uint8*) _msense, sizeof(_msense));
}
}
_thread_return_dfa(k_command_passed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_mode_select()
//
// Declaration:
// void dfa_lun_mode_select(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_mode_select(void)reentrant
{
uint8 dummy;
TRACE0(143, lun, 0, "dfa_lun_mode_select()");
// must consume all data coming from host... throw away
stream_open(k_rx_pipe, k_data_out);
while (_mscbot_has_residue())
{
_mscbot_decr_residue(stream_get(k_rx_pipe, &dummy));
}
stream_close(k_rx_pipe);
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_read_format_capacity()
//
// Declaration:
// void dfa_lun_read_format_capacity(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_read_format_capacity(void)reentrant
{
t_uw16 alloc_length ;
TRACE0(144, lun, 0, "dfa_lun_read_format_capacity() - virtual method - may be overridden");
alloc_length.u16 = (((t_scsi_cb*) &g_bot_cbw.cdb[0])->param.read_format_capacity.allocation_len) ;
TRACE1(145, lun, 0, "rd_fmt_cap alloc_length = %d bytes", alloc_length.u16) ;
if ( _u16_equ_0(alloc_length) )
{
_lun_data(sensep) = &sense_none ;
_thread_return_dfa(k_command_passed) ;
}
stream_open(2, k_data_in);
if ( alloc_length.u16 >= 0x0004 )
{
// write list header - 8 bytes to follow
stream_put(2, 0);
stream_put(2, 0);
stream_put(2, 0);
stream_put(2, 8);
_mscbot_decr_residue(4);
if ( alloc_length.u16 >= 0x000c )
{
TRACE2(146, lun, 0, "read format capacity max lba:%04X%04X", _hw(_lun_data(capacity.lba_max.u32)), _lw(_lun_data(capacity.lba_max.u32)));
stream_put(2, _lun_data(capacity.lba_max.u8.hi )) ;
stream_put(2, _lun_data(capacity.lba_max.u8.lh )) ;
stream_put(2, _lun_data(capacity.lba_max.u8.hl )) ;
stream_put(2, _lun_data(capacity.lba_max.u8.lo )) ;
TRACE2(147, lun, 0, "read format capacity lba size:%04X%04X", _hw(_lun_data(capacity.lba_sz.u32)), _lw(_lun_data(capacity.lba_sz.u32)));
stream_put(2, _lun_data(capacity.lba_sz.u8.hi)) ;
stream_put(2, _lun_data(capacity.lba_sz.u8.lh)) ;
stream_put(2, _lun_data(capacity.lba_sz.u8.hl)) ;
stream_put(2, _lun_data(capacity.lba_sz.u8.lo)) ;
_mscbot_decr_residue(8) ;
}
}
else
{
stream_flush(2) ;
stream_close(2) ;
_lun_data(sensep) = &sense_illegal_length ;
_thread_return_dfa(k_command_failed) ;
}
if (_mscbot_has_residue())
{
// only flush if we have residue... otherwise, we could accidentally zlp the CSW transaction
stream_flush(2);
}
stream_close(2);
_lun_data(sensep) = &sense_none;
_thread_return_dfa(k_command_passed) ;
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_format_unit()
//
// Declaration:
// void dfa_lun_format_unit(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_format_unit(void)reentrant
{
TRACE0(148, lun, 0, "dfa_lun_format_unit() - error: pure virtual method must be overridden");
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_start_stop_unit()
//
// Declaration:
// void dfa_lun_start_stop_unit(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_start_stop_unit(void)reentrant
{
t_bool immed ;
uint8 action ;
uint8 pc ;
t_result result ;
TRACE0(149, lun, 0, "dfa_lun_start_stop_unit()") ;
immed = (((t_scsi_cb*) &g_bot_cbw.cdb[0])->param.start_stop_unit.opts & kbm_scsi_ssu_msk_immed)?k_true:k_false;
pc = (((t_scsi_cb*) &g_bot_cbw.cdb[0])->param.start_stop_unit.pc_action & kbm_scsi_ssu_msk_pc) ;
action= (((t_scsi_cb*) &g_bot_cbw.cdb[0])->param.start_stop_unit.pc_action & kbm_scsi_ssu_msk_action) ;
_lun_data(sensep) = &sense_illegal_request;
result = k_error ;
TRACE1(150, lun, 0, " start-stop immediate: %d", immed) ;
switch (pc)
{
case k_scsi_ssu_pc_nc :
TRACE0(151, lun, 3, "No change in power control") ;
break;
case k_scsi_ssu_pc_active :
TRACE0(152, lun, 3, "Device -> ACTIVE") ;
break;
case k_scsi_ssu_pc_idle :
TRACE0(153, lun, 3, "Device -> IDLE") ;
break;
case k_scsi_ssu_pc_standby :
TRACE0(154, lun, 3, "Device -> STANDBY") ;
break;
case k_scsi_ssu_pc_sleep :
TRACE0(155, lun, 3, "Device -> SLEEP") ;
break;
case k_scsi_ssu_pc_dev_ctl :
TRACE0(156, lun, 3, "Xfer Power Control to Device") ;
break;
case k_scsi_ssu_pc_idle_cdm_0 :
TRACE0(157, lun, 3, "Force Device IDLE Timer to 0") ;
break ;
case k_scsi_ssu_pc_standby_cdm_0 :
TRACE0(158, lun, 3, "Force Device STANDBY Timer to 0") ;
break;
default:
TRACE1(159, lun, 0, "reserved power control code - %02X", pc) ;
break;
}
TRACE1(160, lun, 0, "action:%02x", action) ;
switch (action)
{
case kbm_scsi_ssu_action_stop:
TRACE0(161, lun, 3, "Stop Device") ;
_lun_data(sensep) = &sense_none;
result = k_command_passed ;
break;
case kbm_scsi_ssu_action_start:
TRACE0(162, lun, 3, "Start Device") ;
if (_lun_is_media_present(g_active_lun))
{
_lun_data(sensep) = &sense_none;
result = k_command_passed ;
}
break;
case kbm_scsi_ssu_action_unload:
if (!(_lun_is_media_removable(g_active_lun)))
break;
TRACE0(163, lun, 3, "Stop & Unload Device") ;
switch (g_active_lun)
{
case k_lun_cf:
trace0(0, dev, 0, "_cf_pwr_off()") ;
_cf_pwr_off();
_ejected(k_lun_cf);
break;
case k_lun_ms:
_ms_pwr_off();
_ejected(k_lun_ms);
break;
case k_lun_sm:
_sm_pwr_off();
_ejected(k_lun_sm);
break;
case k_lun_sd:
case k_lun_mmc:
// it is desireable to power the card off here, but that
// causes an insert/eject interrupt...
irq_control(k_irq_sd_insert_eject, kbm_irqctl_clear |kbm_irqctl_mask);
trace0(0, dev, 0, "turning power off");
_sd_pwr_off();
// this seems like a long time, but its an eject from the host, so
// speed is not critical, and 25msec is long enough to "debounce"
// the power off and avoid the tedious insert/eject interrupt
thread_set_timer(25);
while (!thread_got_sync(kbm_sync_timer));
irq_control(k_irq_sd_insert_eject, kbm_irqctl_clear |kbm_irqctl_unmask);
_lun_map_log2phy(k_log_lun_sd, k_lun_sd);
// the _xx_ejected() macros clear the x_crd_ps kbm_crd_ps_sd/kbm_crd_ps_mmc bits
// which causes the new SD probing code in device.c to activate.
// thus after an eject command from the host the SD prober fires and
// reloads the media on XP and OSX. this should keep it ejected until
// it is physically removed and then re-inserted.
//_sd_ejected();
_lun_data_wr(k_lun_sd, media, _lun_data_rd(k_lun_sd, media)&~(kbm_lun_media_present|kbm_lun_media_unknown|kbm_lun_media_changed));
//_mmc_ejected();
_lun_data_wr(k_lun_mmc, media, _lun_data_rd(k_lun_mmc, media)&~(kbm_lun_media_present|kbm_lun_media_unknown|kbm_lun_media_changed));
break;
}
_lun_data(sensep) = &sense_none;
result = k_command_passed ;
break;
case kbm_scsi_ssu_action_load:
TRACE0(164, lun, 3, "Load & Start Device") ;
if (_lun_is_media_removable(g_active_lun))
break;
if (_lun_is_media_present(g_active_lun))
{
_lun_data(sensep) = &sense_none;
result = k_command_passed ;
}
else
{
_lun_data(sensep) = &sense_no_media;
}
break;
}
_thread_return_dfa(result);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_prevent_allow_access()
//
// Declaration:
// void dfa_lun_prevent_allow_access(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_prevent_allow_access(void)reentrant
{
if (g_bot_cbw.cdb[4] & 0x01)
{
TRACE0(165, lun, 0, "dfa_lun_prevent_allow_access(prevent) - warning: impossible to control with this hardware");
_lun_data(sensep) = &sense_illegal_cmdpkt;
_thread_return_dfa(k_command_failed);
}
TRACE0(166, lun, 0, "dfa_lun_prevent_allow_access(allow) - warning: impossible to control with this hardware");
_lun_data(sensep) = &sense_none;
_thread_return_dfa(k_command_passed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_sync_cache()
//
// Declaration:
// void dfa_lun_sync_cache(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_sync_cache(void)reentrant
{
TRACE0(167, lun, 0, "dfa_lun_sync_cache() - warning: not implemented");
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_erase_media()
//
// Declaration:
// void dfa_lun_erase_media(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - luns that support erasing the media should override this function
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_erase_media(void) reentrant
{
TRACE0(168, lun, 0, "dfa_lun_erase_media() - not implemented on this lun");
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_report_media_geometry()
//
// Declaration:
// void dfa_lun_report_media_geometry(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - luns that support mapped media override this function
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_report_media_geometry(void) reentrant
{
TRACE0(169, lun, 0, "dfa_lun_report_media_geometry() - not implemented on this lun");
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_secure_memory_write()
//
// Declaration:
// void dfa_lun_secure_memory_write(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - should not be overridden. Vendor specific command. independant of what lun it is
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_secure_memory_write(void) reentrant
{
uint8 i, len;
TRACE0(170, lun, 0, "dfa_lun_secure_memory_write()");
_lun_data(sensep) = &sense_none;
len = g_bot_cbw.cdb[8];
// receive the data
if (k_success != mscbot_rx_data_buffer(g_sector_buffer, len))
_thread_return_dfa(k_command_failed);
//get the nvstore ready to write
nvstore_write_enable();
for (i= 0; i < len; i++)
{
//TRACE2(387, lun, 0, "buffer[%d] = %02x",i,g_sector_buffer[i]);
nvstore_write((k_ix_secure_mem + i), g_sector_buffer[i]);
}
//Post write operation
nvstore_write_disable();
//verify the writes
for (i=0; i < len; i++)
{
if (nvstore_read((k_ix_secure_mem + i)) != g_sector_buffer[i])
{
_thread_return_dfa(k_command_failed);
}
}
_mscbot_decr_residue(len); //Decrement the residue
_thread_return_dfa(k_command_passed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_secure_memory_read()
//
// Declaration:
// void dfa_lun_secure_memory_read(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - should not be overridden. Vendor specific command. independant of what lun it is
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_secure_memory_read(void) reentrant
{
uint8 i, len;
TRACE0(171, lun, 0, "dfa_lun_secure_memory_read()");
_lun_data(sensep) = &sense_none;
len = g_bot_cbw.cdb[8];
for (i= 0; i < len; i++)
{
g_sector_buffer[i] = nvstore_read((k_ix_secure_mem + i));
}
// send it
mscbot_tx_data_buffer(g_sector_buffer, len);
_thread_return_dfa(k_command_passed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_device_diagnostics()
//
// Declaration:
// void dfa_lun_device_diagnostics(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_device_diagnostics(void) reentrant
{
TRACE0(172, lun, 0, "dfa_lun_device_diagnostics() - warning: not implemented");
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_unsupported()
//
// Declaration:
// void dfa_lun_unsupported(void) reentrant ;
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void dfa_lun_unsupported(void) reentrant
{
TRACE0(173, lun, 0, "dfa_lun_unsupported() - warning: host delivered unsupported command");
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_inquiry()
//
// Declaration:
// void dfa_lun_inquiry(void) reentrant ;
//
// Purpose:
// Default mass storage class inquiry handling, utilizing
// info that should be present in the _lun_data instances
// during lun initialization.
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
// - Should not need to be overridden. This function will automatically use
// lun instance data to respond to the host.
//
// Since:
// atapi.20
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
// clearly we need "nvstore.h", but since brian has device.c checked out,
// and as usual i'm in a hurry, i'll do a smidegon of hackmeistering to
// quick-n-dirty this. the enterprising reader should take it upon his/herself
// to fabricate nvstore.h and nvstore.c
//
// offsets into the nvstore - COMBINE THESE WITH THOSE IN DEVICE.C AND PUT INTO DEV.H!!!
#define k_ix_mfr 34
#define k_sz_mfr 60
#define k_ix_prd 94
#define k_sz_prd 60
#define k_ix_vid_lo 26
#define k_ix_vid_hi 27
#define k_ix_pid_lo 28
#define k_ix_pid_hi 29
//------------------------------------------------------------------------------
#define k_sz_lun_inquiry 36
#define kbm_inquiry_rmb 0x80
code uint8 lun_inquiry_template[k_sz_lun_inquiry] =
{
0x00, // PeripheralDeviceType = DASD
0x00, // Removable bit set in process_inquiry
0x00, // IsoEcmaAnsiVersion
0x02, // ResponseDataFormat
0x20, // AdditionalLength
0x00, 0x00, 0x00, // Reserved[3]
// VendorInfo[8]
'S', 'M', 'S', 'C', 0, 0, 0, 0,
// ProductInfo[16]
'U', 'S', 'B', ' ', '2', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
'0' + kbcd_dev_version_major, // ProductVersion[0]
'.', // ProductVersion[1]
'0' + (kbcd_dev_version_minor >> 4), // ProductVersion[2]
'0' + (kbcd_dev_version_minor & 0x0F) // ProductVersion[3]
};
//------------------------------------------------------------------------------
void dfa_lun_inquiry(void) reentrant
{
uint8 length;
// uint8 pnr;
uint8 off;
uint8 n;
TRACE0(174, lun, 0, "dfa_lun_inquiry()");
TRACE1(175, lun, 0, "alloc length:%02X", g_bot_cbw.cdb[4]);
// load template into buffer
memcpy((uint8 xdata *)g_sector_buffer, (uint8 code *)lun_inquiry_template, k_sz_lun_inquiry);
// offset 1: overwrite the rmb bit
g_sector_buffer[1] = (_lun_is_media_removable(g_active_lun))
? lun_inquiry_template[1] |kbm_inquiry_rmb
: lun_inquiry_template[1] & ~kbm_inquiry_rmb;
// offset 8..15: overwrite the vendor up to 8 chars from the mfg string dscr
memcpy(g_sector_buffer+8, g_inq_vid, k_sz_inq_vid);
// offset 16..<24>: overwrite the product up to 9 chars from the Inquiry Prd ID header
memcpy(g_sector_buffer+16, g_inq_pid_hdr, k_sz_inq_pid_hdr) ;
off=16+k_sz_inq_pid_hdr;
// offset <16>..<16>+5: _XS-, should always be HS as per jwc
g_sector_buffer[off++] = ' ';
g_sector_buffer[off++] = 'H';
g_sector_buffer[off++] = 'S';
g_sector_buffer[off++] = '-';
// offset <16>+3..31: lun device id
n = k_sz_lun_inquiry - off - 4;
memcpy(g_sector_buffer + off, _lun_data(device_id), _min(n, k_lun_max_devid_sz));
// send it
length = _min(k_sz_lun_inquiry, g_bot_cbw.cdb[4]);
mscbot_tx_data_buffer(g_sector_buffer, length) ;
_thread_return_dfa(k_command_passed);
}
//+-----------------------------------------------------------------------------
// Name:
// lun_process_cb2()
//
// Declaration:
// void lun_process_cb2() reentrant
//
// Purpose:
//
// Arguments:
//
// Return:
//
// Notes:
//
// Since:
// fmc-1.0
//------------------------------------------------------------------------------
void lun_process_cb2(void) reentrant;
void lun_process_cb2() reentrant
{
uint8 cmd = g_bot_cbw.cdb[0];
TRACE2(176, lun, 0, "lun_process_cb2(lun:%d, cmd:%02x)", g_active_lun, cmd);
// _stack_check();
// _stack_dump();
// run these regardless of current sense code - they cannot be failed for any reason
if (cmd == k_protocol_inquiry)
{
TRACE0(177, lun, 0, "cb-inquiry");
thread_run_dfa(_dfa_lun_inquiry(), thread_rd_dfa_argp(), thread_end_dfa);
}
if (cmd == k_protocol_request_sense)
{
TRACE0(178, lun, 0, "cb-request-sense");
thread_run_dfa(_dfa_lun_req_sense(), thread_rd_dfa_argp(), thread_end_dfa);
}
if (cmd == k_protocol_vendor_secure_memory_write)
{
TRACE0(179, lun, 0, "cb-protocol-vendor-secure-memory-write");
thread_run_dfa(_dfa_lun_secure_memory_write(), thread_rd_dfa_argp(), thread_end_dfa);
}
if (cmd == k_protocol_vendor_secure_memory_read)
{
TRACE0(180, lun, 0, "cb-protocol-vendor-secure-memory-read");
thread_run_dfa(_dfa_lun_secure_memory_read(), thread_rd_dfa_argp(), thread_end_dfa);
}
if(cmd==k_protocol_vendor)
{
uint8 cmd2=g_bot_cbw.cdb[1];
if(cmd2==k_vendor_erase_media)
{
TRACE0(181, lun, 0, "vendor specific: erase media");
thread_run_dfa(_dfa_lun_erase_media(), thread_rd_dfa_argp(), thread_end_dfa);
}
else if(cmd2==k_vendor_report_media_geometry)
{
TRACE0(182, lun, 0, "vendor specific: report media geometry");
thread_run_dfa(_dfa_lun_report_media_geometry(), thread_rd_dfa_argp(), thread_end_dfa);
}
}
// check if there is an error condition
if (_lun_data(sensep) != &sense_none)
{
TRACE0(183, lun, 99, "unhappy sensep");
_thread_return_dfa(k_command_failed);
}
// dispatch the command to the a virtual handler
switch (cmd)
{
// BBB: the first optimization to this was to call rd/wr directly from dfa_lun_process_cb.
// that eliminated a dfa layer (55usec push, 66usec pop) and required no changes to dfa's.
// the second optimization was to call rd/wr directly from dev_thread_wait_cbw.
// that eliminated another dfa layer cutting out 240 to 270 usec in toto (as measured)
// but required a changes to dfa's. so these are no longer called from here.
#if 0
case k_protocol_read_10:
case k_protocol_read_12:
TRACE0(184, lun, 0, "cb-read");
//thread_run_dfa(_dfa_lun_read(), thread_rd_dfa_argp(), thread_end_dfa);
(*_dfa_lun_read(g_active_lun))();
case k_protocol_write_10:
case k_protocol_write_12:
TRACE0(185, lun, 0, "cb-write");
//thread_run_dfa(_dfa_lun_write(), thread_rd_dfa_argp(), thread_end_dfa);
(*_dfa_lun_write(g_active_lun))();
#endif
case k_protocol_verify_10:
TRACE0(186, lun, 0, "cb-verify");
thread_run_dfa(_dfa_lun_verify(), thread_rd_dfa_argp(), thread_end_dfa);
// 04/17/02 tbh - added to report the wr bit to prevent write commands to rom only ms cards
case k_protocol_mode_sense_6:
TRACE0(187, lun, 0, "cb-mode-sense6");
thread_run_dfa(_dfa_lun_mode_sense(), thread_rd_dfa_argp(), thread_end_dfa);
case k_protocol_mode_sense_10:
TRACE0(188, lun, 0, "cb-mode-sense10");
thread_run_dfa(_dfa_lun_mode_sense(), thread_rd_dfa_argp(), thread_end_dfa);
#if 0
case k_protocol_mode_select_10:
TRACE0(189, lun, 0, "cb-mode-select");
thread_run_dfa(_dfa_lun_mode_select(), thread_rd_dfa_argp(), thread_end_dfa);
#endif
case k_protocol_test_unit_ready:
TRACE0(190, lun, 0, "cb-test-unit-ready");
thread_run_dfa(_dfa_lun_test_unit_ready(), thread_rd_dfa_argp(), thread_end_dfa);
case k_protocol_read_capacity:
TRACE0(191, lun, 0, "cb-read-capacity");
thread_run_dfa(_dfa_lun_read_capacity(), thread_rd_dfa_argp(), thread_end_dfa);
case k_protocol_format_unit:
TRACE0(192, lun, 0, "cb-format-unit");
thread_run_dfa(_dfa_lun_format_unit(), thread_rd_dfa_argp(), thread_end_dfa);
case k_protocol_start_stop_unit:
TRACE0(193, lun, 0, "cb-start-stop-unit");
thread_run_dfa(_dfa_lun_start_stop_unit(), thread_rd_dfa_argp(), thread_end_dfa);
case k_protocol_prevent_allow_medium_remval:
TRACE0(194, lun, 0, "cb-prevent-allow-mediaum-removal");
thread_run_dfa(_dfa_lun_prevent_allow_access(), thread_rd_dfa_argp(), thread_end_dfa);
case k_protocol_synchronize_cache:
TRACE0(195, lun, 0, "cb-synchronize-cache");
thread_run_dfa(_dfa_lun_sync_cache(), thread_rd_dfa_argp(), thread_end_dfa);
case k_protocol_read_format_capacities:
TRACE0(196, lun, 0, "cb-read-format-capacities");
thread_run_dfa(_dfa_lun_read_format_capacity(), thread_rd_dfa_argp(), thread_end_dfa);
default:
TRACE0(197, lun, 0, "cb unknown");
_lun_data(sensep) = &sense_illegal_opcode;
_thread_return_dfa(k_command_failed);
}
dev_exception(k_err_unreachable_code+16);
}
//+-----------------------------------------------------------------------------
// Name:
// dfa_lun_process_cb()
//
// Declaration:
// void dfa_lun_process_cb(void) reentrant ;
//
// Purpose:
// dfa entrypoint for mass storage class handler. This dfa is called
// to activate the target lun before dispatching the command. This
// allows subsequent lun-specific and lun-generic dfas to know that
// they are the active lun by the time their dfa is invoked.
//
// Arguments:
//
// Return:
//
// Notes:
// - This is a dfa.
//
// Since:
// atapi.20
//------------------------------------------------------------------------------
void dfa_lun_process_cb() reentrant
{
TRACE1(198, lun, 99, "dfa_lun_process_cb(lun:%d)", g_active_lun);
TRACE2(199, lun, 99, "cb:_lun_data(%d, media):0x%02X", g_active_lun, _lun_data_rd(1, media));
// if there is media present it may need identification
if (!_lun_is_media_present(g_active_lun))
{
TRACE0(200, lun, 99, "dfa_lun_process_cb is setting sense_no_media here");
_lun_data(sensep) = &sense_no_media;
}
else
if (_lun_is_media_changed(g_active_lun))
{
//!!! this is tedious if the previous command caused an identify media
// and that failed... the media change keeps repeating...
TRACE0(201, lun, 99, "dfa_lun_process_cb is setting sense_media_changed here");
_lun_data(sensep) = &sense_media_change;
}
else
if (_lun_data(media) & kbm_lun_media_unknown)
{
TRACE0(202, lun, 99, "dfa_lun_process_cb has decided to identify the media");
thread_run_dfa(_dfa_lun_identify_media(), thread_rd_dfa_argp(), lun_process_cb2);
}
lun_process_cb2();
}
//---eof------------------------------------------------------------------------