1230557Sjimharris/*-
2230557Sjimharris * This file is provided under a dual BSD/GPLv2 license.  When using or
3230557Sjimharris * redistributing this file, you may do so under either license.
4230557Sjimharris *
5230557Sjimharris * GPL LICENSE SUMMARY
6230557Sjimharris *
7230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
8230557Sjimharris *
9230557Sjimharris * This program is free software; you can redistribute it and/or modify
10230557Sjimharris * it under the terms of version 2 of the GNU General Public License as
11230557Sjimharris * published by the Free Software Foundation.
12230557Sjimharris *
13230557Sjimharris * This program is distributed in the hope that it will be useful, but
14230557Sjimharris * WITHOUT ANY WARRANTY; without even the implied warranty of
15230557Sjimharris * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16230557Sjimharris * General Public License for more details.
17230557Sjimharris *
18230557Sjimharris * You should have received a copy of the GNU General Public License
19230557Sjimharris * along with this program; if not, write to the Free Software
20230557Sjimharris * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
21230557Sjimharris * The full GNU General Public License is included in this distribution
22230557Sjimharris * in the file called LICENSE.GPL.
23230557Sjimharris *
24230557Sjimharris * BSD LICENSE
25230557Sjimharris *
26230557Sjimharris * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
27230557Sjimharris * All rights reserved.
28230557Sjimharris *
29230557Sjimharris * Redistribution and use in source and binary forms, with or without
30230557Sjimharris * modification, are permitted provided that the following conditions
31230557Sjimharris * are met:
32230557Sjimharris *
33230557Sjimharris *   * Redistributions of source code must retain the above copyright
34230557Sjimharris *     notice, this list of conditions and the following disclaimer.
35230557Sjimharris *   * Redistributions in binary form must reproduce the above copyright
36230557Sjimharris *     notice, this list of conditions and the following disclaimer in
37230557Sjimharris *     the documentation and/or other materials provided with the
38230557Sjimharris *     distribution.
39230557Sjimharris *
40230557Sjimharris * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41230557Sjimharris * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42230557Sjimharris * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
43230557Sjimharris * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
44230557Sjimharris * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45230557Sjimharris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
46230557Sjimharris * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47230557Sjimharris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48230557Sjimharris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49230557Sjimharris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
50230557Sjimharris * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51230557Sjimharris */
52230557Sjimharris
53230557Sjimharris#include <sys/cdefs.h>
54230557Sjimharris__FBSDID("$FreeBSD$");
55230557Sjimharris
56230557Sjimharris/**
57230557Sjimharris * @file
58230557Sjimharris * @brief This file contains the method implementations required to
59230557Sjimharris *        translate the SCSI unmap command.
60230557Sjimharris */
61230557Sjimharris
62230557Sjimharris#if !defined(DISABLE_SATI_UNMAP)
63230557Sjimharris
64230557Sjimharris#include <dev/isci/scil/sati_unmap.h>
65230557Sjimharris#include <dev/isci/scil/sati_callbacks.h>
66230557Sjimharris#include <dev/isci/scil/sati_translator_sequence.h>
67230557Sjimharris#include <dev/isci/scil/sati_util.h>
68230557Sjimharris#include <dev/isci/scil/intel_ata.h>
69230557Sjimharris#include <dev/isci/scil/intel_scsi.h>
70230557Sjimharris#include <dev/isci/scil/intel_sat.h>
71230557Sjimharris
72230557Sjimharris//******************************************************************************
73230557Sjimharris//* P R I V A T E   M E T H O D S
74230557Sjimharris//******************************************************************************
75230557Sjimharris
76230557Sjimharris/**
77230557Sjimharris * @brief This method translates a given number of DSM
78230557Sjimharris *        requests into DSM blocks based on the devices logical block size
79230557Sjimharris *
80230557Sjimharris * @return Number of DSM blocks required for the DSM descriptor count
81230557Sjimharris */
82230557SjimharrisU32 sati_unmap_calculate_dsm_blocks(
83230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
84230557Sjimharris   U32                          dsm_descriptor_count
85230557Sjimharris)
86230557Sjimharris{
87230557Sjimharris   U32 blocks = (dsm_descriptor_count * sizeof(TRIM_PAIR))/sequence->device->logical_block_size;
88230557Sjimharris   if ((dsm_descriptor_count * sizeof(TRIM_PAIR)) % sequence->device->logical_block_size)
89230557Sjimharris   {
90230557Sjimharris       blocks++;
91230557Sjimharris   }
92230557Sjimharris   return blocks;
93230557Sjimharris}
94230557Sjimharris
95230557Sjimharris/**
96230557Sjimharris * @brief This method performs the SCSI Unmap command translation
97230557Sjimharris *        functionality.
98230557Sjimharris *        This includes:
99230557Sjimharris *        - setting the command register
100230557Sjimharris *        - setting the device head register
101230557Sjimharris *        - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
102230557Sjimharris *        For more information on the parameters passed to this method,
103230557Sjimharris *        please reference sati_translate_command().
104230557Sjimharris *
105230557Sjimharris * @return Indicate if the method was successfully completed.
106230557Sjimharris * @retval SATI_SUCCESS This is returned in all other cases.
107230557Sjimharris */
108230557SjimharrisSATI_STATUS sati_unmap_construct(
109230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
110230557Sjimharris   void                       * scsi_io,
111230557Sjimharris   void                       * ata_io,
112230557Sjimharris   U32                          sector_count
113230557Sjimharris)
114230557Sjimharris{
115230557Sjimharris   U8 * h2d_register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
116230557Sjimharris   U8 * d2h_register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
117230557Sjimharris
118230557Sjimharris   sati_set_ata_command(h2d_register_fis, ATA_DATA_SET_MANAGEMENT);
119230557Sjimharris   sati_set_ata_features(h2d_register_fis, 0x01);
120230557Sjimharris   sati_set_ata_sector_count(h2d_register_fis, (U8)sector_count);
121230557Sjimharris   sati_set_ata_device_head(h2d_register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE);
122230557Sjimharris
123230557Sjimharris   // Set the completion status since the core will not do that for
124230557Sjimharris   // the udma fast path.
125230557Sjimharris   sati_set_ata_status(d2h_register_fis, 0x00);
126230557Sjimharris
127230557Sjimharris   // Set up the direction and protocol for SCIC
128230557Sjimharris   sequence->data_direction                 = SATI_DATA_DIRECTION_OUT;
129230557Sjimharris   sequence->protocol                       = SAT_PROTOCOL_UDMA_DATA_OUT;
130230557Sjimharris   // The UNMAP translation will always require a callback
131230557Sjimharris   // on every response so it can free memory if an error
132230557Sjimharris   // occurs.
133230557Sjimharris   sequence->is_translate_response_required = TRUE;
134230557Sjimharris
135230557Sjimharris   ASSERT(sector_count < 0x100);
136230557Sjimharris
137230557Sjimharris   return SATI_SUCCESS;
138230557Sjimharris}
139230557Sjimharris
140230557Sjimharris/**
141230557Sjimharris * @brief This method updates the unmap sequence state to the next
142230557Sjimharris *        unmap descriptor
143230557Sjimharris *
144230557Sjimharris * @return Indicate if the method was successfully completed.
145230557Sjimharris * @retval SATI_SUCCESS This is returned in all other cases.
146230557Sjimharris */
147230557SjimharrisSATI_STATUS sati_unmap_load_next_descriptor(
148230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
149230557Sjimharris   void                       * scsi_io
150230557Sjimharris)
151230557Sjimharris{
152230557Sjimharris   SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
153230557Sjimharris   U32                             index;
154230557Sjimharris   U8                              unmap_block_descriptor[16];
155230557Sjimharris
156230557Sjimharris   unmap_process_state = &sequence->command_specific_data.unmap_process_state;
157230557Sjimharris
158230557Sjimharris   // Load the next descriptor
159230557Sjimharris   for(index = unmap_process_state->current_unmap_block_descriptor_index;
160230557Sjimharris       index < unmap_process_state->current_unmap_block_descriptor_index +
161230557Sjimharris               SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
162230557Sjimharris       index++)
163230557Sjimharris   {
164230557Sjimharris      sati_get_data_byte(sequence,
165230557Sjimharris         scsi_io,
166230557Sjimharris         index,
167230557Sjimharris         &unmap_block_descriptor[index-unmap_process_state->current_unmap_block_descriptor_index]);
168230557Sjimharris   }
169230557Sjimharris
170230557Sjimharris   // Update the internal state for the next translation pass
171230557Sjimharris   unmap_process_state->current_lba_count = (unmap_block_descriptor[8] << 24) |
172230557Sjimharris                                            (unmap_block_descriptor[9] << 16) |
173230557Sjimharris                                            (unmap_block_descriptor[10] << 8) |
174230557Sjimharris                                            (unmap_block_descriptor[11]);
175230557Sjimharris   unmap_process_state->current_lba       = ((SATI_LBA)(unmap_block_descriptor[0]) << 56) |
176230557Sjimharris                                            ((SATI_LBA)(unmap_block_descriptor[1]) << 48) |
177230557Sjimharris                                            ((SATI_LBA)(unmap_block_descriptor[2]) << 40) |
178230557Sjimharris                                            ((SATI_LBA)(unmap_block_descriptor[3]) << 32) |
179230557Sjimharris                                            ((SATI_LBA)(unmap_block_descriptor[4]) << 24) |
180230557Sjimharris                                            ((SATI_LBA)(unmap_block_descriptor[5]) << 16) |
181230557Sjimharris                                            ((SATI_LBA)(unmap_block_descriptor[6]) << 8) |
182230557Sjimharris                                            ((SATI_LBA)(unmap_block_descriptor[7]));
183230557Sjimharris   unmap_process_state->next_lba          = 0;
184230557Sjimharris
185230557Sjimharris   // Update the index for the next descriptor to translate
186230557Sjimharris   unmap_process_state->current_unmap_block_descriptor_index += SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
187230557Sjimharris
188230557Sjimharris   return SATI_SUCCESS;
189230557Sjimharris}
190230557Sjimharris
191230557Sjimharris/**
192230557Sjimharris * @brief This method determines the max number of blocks of DSM data
193230557Sjimharris *        that can be satisfied by the device and the SW
194230557Sjimharris *
195230557Sjimharris * @return Number of blocks supported
196230557Sjimharris * @retval Number of blocks supported
197230557Sjimharris */
198230557SjimharrisU32 sati_unmap_get_max_buffer_size_in_blocks(
199230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence
200230557Sjimharris)
201230557Sjimharris{
202230557Sjimharris   // Currently this SATI implementation only supports a single
203230557Sjimharris   // 4k block of memory for the DMA write operation for simplicity
204230557Sjimharris   // (no need to handle more than one SG element).
205230557Sjimharris   // Since most run time UNMAP requests use 1K or less buffer space,
206230557Sjimharris   // there is no performance degradation with only supporting a
207230557Sjimharris   // single physical page.  For best results allocate the maximum
208230557Sjimharris   // amount of memory the device can handle up to the maximum of 4K.
209230557Sjimharris   return MIN(SATI_DSM_MAX_BUFFER_SIZE/sequence->device->logical_block_size,
210230557Sjimharris              sequence->device->max_lba_range_entry_blocks);
211230557Sjimharris}
212230557Sjimharris
213230557Sjimharris/**
214230557Sjimharris * @brief This method will be called before starting the first unmap translation
215230557Sjimharris *
216230557Sjimharris * @return Indicate if the translation was successful.
217230557Sjimharris * @retval SATI_SUCCESS This is returned if the command translation was
218230557Sjimharris *         successful and no further processing.
219230557Sjimharris * @retval SATI_COMPLETE - The initial processing was completed successfully
220230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA - Failed the initial processing
221230557Sjimharris */
222230557SjimharrisSATI_STATUS sati_unmap_initial_processing(
223230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
224230557Sjimharris   void                       * scsi_io,
225230557Sjimharris   void                       * ata_io
226230557Sjimharris)
227230557Sjimharris{
228230557Sjimharris   SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
229230557Sjimharris   U8 * cdb;
230230557Sjimharris   U16 unmap_length;
231230557Sjimharris   U32 descriptor_length;
232230557Sjimharris   U32 index;
233230557Sjimharris   U32 max_dsm_blocks;
234230557Sjimharris   U8  unmap_param_list[8];
235230557Sjimharris
236230557Sjimharris   unmap_process_state = &sequence->command_specific_data.unmap_process_state;
237230557Sjimharris
238230557Sjimharris   // Set up the sequence type for unmap translation
239230557Sjimharris   sequence->type = SATI_SEQUENCE_UNMAP;
240230557Sjimharris
241230557Sjimharris   // Make sure the device is TRIM capable
242230557Sjimharris   if ((sequence->device->capabilities & SATI_DEVICE_CAP_DSM_TRIM_SUPPORT)
243230557Sjimharris       != SATI_DEVICE_CAP_DSM_TRIM_SUPPORT)
244230557Sjimharris   {
245230557Sjimharris      // Can't send TRIM request to device that does not support it
246230557Sjimharris      sati_scsi_sense_data_construct(
247230557Sjimharris         sequence,
248230557Sjimharris         scsi_io,
249230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
250230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
251230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_CDB,
252230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_CDB
253230557Sjimharris      );
254230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
255230557Sjimharris   }
256230557Sjimharris
257230557Sjimharris   // get the amount of data being sent from the cdb
258230557Sjimharris   cdb = sati_cb_get_cdb_address(scsi_io);
259230557Sjimharris   unmap_length = (sati_get_cdb_byte(cdb, 7) << 8) | sati_get_cdb_byte(cdb, 8);
260230557Sjimharris
261230557Sjimharris   // If nothing has been requested return success now.
262230557Sjimharris   if (unmap_length == 0)
263230557Sjimharris   {
264230557Sjimharris       // SAT: This is not an error
265230557Sjimharris       return SATI_SUCCESS;
266230557Sjimharris   }
267230557Sjimharris   if (unmap_length < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST)
268230557Sjimharris   {
269230557Sjimharris      // Not enough length specified in the CDB
270230557Sjimharris      sati_scsi_sense_data_construct(
271230557Sjimharris         sequence,
272230557Sjimharris         scsi_io,
273230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
274230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
275230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_CDB,
276230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_CDB
277230557Sjimharris      );
278230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
279230557Sjimharris   }
280230557Sjimharris
281230557Sjimharris   sequence->allocation_length = unmap_length;
282230557Sjimharris
283230557Sjimharris   // Get the unmap parameter header
284230557Sjimharris   for(index = 0; index < SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST; index++)
285230557Sjimharris   {
286230557Sjimharris      sati_get_data_byte(sequence, scsi_io, index,   &unmap_param_list[index]);
287230557Sjimharris   }
288230557Sjimharris   descriptor_length = (unmap_param_list[2] << 8) | unmap_param_list[3];
289230557Sjimharris
290230557Sjimharris   // Check length again
291230557Sjimharris   if (descriptor_length == 0)
292230557Sjimharris   {
293230557Sjimharris       // SAT: This is not an error
294230557Sjimharris       return SATI_SUCCESS;
295230557Sjimharris   }
296230557Sjimharris
297230557Sjimharris   if ((U32)(unmap_length - SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST) < descriptor_length)
298230557Sjimharris   {
299230557Sjimharris      // Not enough length specified in the CDB
300230557Sjimharris      sati_scsi_sense_data_construct(
301230557Sjimharris         sequence,
302230557Sjimharris         scsi_io,
303230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
304230557Sjimharris         SCSI_SENSE_ILLEGAL_REQUEST,
305230557Sjimharris         SCSI_ASC_INVALID_FIELD_IN_CDB,
306230557Sjimharris         SCSI_ASCQ_INVALID_FIELD_IN_CDB
307230557Sjimharris      );
308230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
309230557Sjimharris   }
310230557Sjimharris
311230557Sjimharris   // Save the maximum unmap block descriptors in this request
312230557Sjimharris   unmap_process_state->max_unmap_block_descriptors =
313230557Sjimharris       descriptor_length/SATI_UNMAP_SIZEOF_SCSI_UNMAP_BLOCK_DESCRIPTOR;
314230557Sjimharris
315230557Sjimharris   // Determine the maximum size of the write buffer that will be required
316230557Sjimharris   // for the translation in terms of number of blocks
317230557Sjimharris   max_dsm_blocks = sati_unmap_get_max_buffer_size_in_blocks(sequence);
318230557Sjimharris
319230557Sjimharris   // Save the maximum number of DSM descriptors we can send during the translation
320230557Sjimharris   unmap_process_state->max_lba_range_entries =
321230557Sjimharris       (max_dsm_blocks*sequence->device->logical_block_size)/sizeof(TRIM_PAIR);
322230557Sjimharris
323230557Sjimharris   // Get the write buffer for the translation
324230557Sjimharris   sati_cb_allocate_dma_buffer(
325230557Sjimharris      scsi_io,
326230557Sjimharris      max_dsm_blocks*sequence->device->logical_block_size,
327230557Sjimharris      &(unmap_process_state->virtual_unmap_buffer),
328230557Sjimharris      &(unmap_process_state->physical_unmap_buffer_low),
329230557Sjimharris      &(unmap_process_state->physical_unmap_buffer_high));
330230557Sjimharris
331230557Sjimharris   // Makes sure we have a buffer
332230557Sjimharris   if (unmap_process_state->virtual_unmap_buffer == NULL)
333230557Sjimharris   {
334230557Sjimharris      // Resource failure
335230557Sjimharris      sati_scsi_sense_data_construct(
336230557Sjimharris         sequence,
337230557Sjimharris         scsi_io,
338239545Sjimharris         SCSI_STATUS_BUSY,
339239545Sjimharris         SCSI_SENSE_NO_SENSE,
340230557Sjimharris         SCSI_ASC_NO_ADDITIONAL_SENSE,
341230557Sjimharris         SCSI_ASCQ_NO_ADDITIONAL_SENSE
342230557Sjimharris      );
343230557Sjimharris      return SATI_FAILURE_CHECK_RESPONSE_DATA;
344230557Sjimharris   }
345230557Sjimharris
346230557Sjimharris   // Get the first SGL entry.  This code will only use one 4K page so will
347230557Sjimharris   // only utilize the first sge.
348230557Sjimharris   sati_cb_sgl_next_sge(scsi_io,
349230557Sjimharris                        ata_io,
350230557Sjimharris                        NULL,
351230557Sjimharris                        &(unmap_process_state->unmap_buffer_sgl_pair));
352230557Sjimharris
353230557Sjimharris   // Load the first descriptor to start the translation loop
354230557Sjimharris   unmap_process_state->current_unmap_block_descriptor_index =
355230557Sjimharris      SATI_UNMAP_SIZEOF_SCSI_UNMAP_PARAMETER_LIST;
356230557Sjimharris   sati_unmap_load_next_descriptor(sequence,scsi_io);
357230557Sjimharris
358230557Sjimharris   // Next state will be incomplete since translation
359230557Sjimharris   // will require a callback and possibly more requests.
360230557Sjimharris   sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
361230557Sjimharris
362230557Sjimharris   return SATI_COMPLETE;
363230557Sjimharris}
364230557Sjimharris
365230557Sjimharris/**
366230557Sjimharris * @brief This method will process each unmap sequence.
367230557Sjimharris *
368230557Sjimharris * @return Indicate if the translation was successful.
369230557Sjimharris * @retval SATI_SUCCESS
370230557Sjimharris */
371230557SjimharrisSATI_STATUS sati_unmap_process(
372230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
373230557Sjimharris   void                       * scsi_io,
374230557Sjimharris   void                       * ata_io
375230557Sjimharris)
376230557Sjimharris{
377230557Sjimharris   SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
378230557Sjimharris   SATI_LBA dsm_descriptor_lba_count;
379230557Sjimharris   U32 dsm_descriptor;
380230557Sjimharris   U32 dsm_bytes;
381230557Sjimharris   U32 dsm_remainder_bytes;
382230557Sjimharris   U32 dsm_blocks;
383230557Sjimharris   U32 max_dsm_blocks;
384230557Sjimharris
385230557Sjimharris   unmap_process_state = &sequence->command_specific_data.unmap_process_state;
386230557Sjimharris
387230557Sjimharris   // Set up the starting address of the buffer for this portion of the translation
388230557Sjimharris   unmap_process_state->current_dsm_descriptor = unmap_process_state->virtual_unmap_buffer;
389230557Sjimharris   dsm_descriptor = 0;
390230557Sjimharris
391230557Sjimharris   // Translate as much as we can
392230557Sjimharris   while ((dsm_descriptor < unmap_process_state->max_lba_range_entries) &&
393230557Sjimharris          (unmap_process_state->current_lba_count > 0)) {
394230557Sjimharris      // See if the LBA count will fit in to a single descriptor
395230557Sjimharris      if (unmap_process_state->current_lba_count > SATI_DSM_MAX_SECTOR_COUNT) {
396230557Sjimharris         // Can't fit all of the lbas for this descriptor in to
397230557Sjimharris         // one DSM request.  Adjust the current LbaCount and total
398230557Sjimharris         // remaining for the next descriptor
399230557Sjimharris         dsm_descriptor_lba_count = SATI_DSM_MAX_SECTOR_COUNT;
400230557Sjimharris         unmap_process_state->current_lba_count -= SATI_DSM_MAX_SECTOR_COUNT;
401230557Sjimharris         unmap_process_state->next_lba =
402230557Sjimharris             unmap_process_state->current_lba + SATI_DSM_MAX_SECTOR_COUNT;
403230557Sjimharris      } else {
404230557Sjimharris         // It all fits in to one descriptor
405230557Sjimharris         dsm_descriptor_lba_count = unmap_process_state->current_lba_count;
406230557Sjimharris         unmap_process_state->current_lba_count = 0;
407230557Sjimharris      }
408230557Sjimharris
409230557Sjimharris      // Fill in the ATA DSM descriptor
410230557Sjimharris      ((PTRIM_PAIR)(unmap_process_state->current_dsm_descriptor))->sector_address =
411230557Sjimharris          unmap_process_state->current_lba;
412230557Sjimharris      ((PTRIM_PAIR)(unmap_process_state->current_dsm_descriptor))->sector_count =
413230557Sjimharris          dsm_descriptor_lba_count;
414230557Sjimharris
415230557Sjimharris      // See if we can move on to the next descriptor
416230557Sjimharris      if (unmap_process_state->current_lba_count == 0) {
417230557Sjimharris         // See if there is another descriptor
418230557Sjimharris         --unmap_process_state->max_unmap_block_descriptors;
419230557Sjimharris         if (unmap_process_state->max_unmap_block_descriptors > 0) {
420230557Sjimharris            // Move on to the next descriptor
421230557Sjimharris            sati_unmap_load_next_descriptor(sequence,scsi_io);
422230557Sjimharris         }
423230557Sjimharris      } else {
424230557Sjimharris         // Move to the next LBA in this descriptor
425230557Sjimharris         unmap_process_state->current_lba = unmap_process_state->next_lba;
426230557Sjimharris      }
427230557Sjimharris
428230557Sjimharris      // Make sure the LBA does not exceed 48 bits...
429230557Sjimharris      ASSERT(unmap_process_state->current_lba <= SATI_DSM_MAX_SECTOR_ADDRESS);
430230557Sjimharris
431230557Sjimharris      // Increment the number of descriptors used and point to the next entry
432230557Sjimharris      dsm_descriptor++;
433230557Sjimharris      unmap_process_state->current_dsm_descriptor =
434230557Sjimharris          (U8 *)(unmap_process_state->current_dsm_descriptor) + sizeof(TRIM_PAIR);
435230557Sjimharris   }
436230557Sjimharris
437230557Sjimharris   // Calculate number of blocks we have filled in
438230557Sjimharris   dsm_blocks     = sati_unmap_calculate_dsm_blocks(sequence,dsm_descriptor);
439230557Sjimharris   dsm_bytes      = dsm_blocks * sequence->device->logical_block_size;
440230557Sjimharris   max_dsm_blocks = sati_unmap_get_max_buffer_size_in_blocks(sequence);
441230557Sjimharris
442230557Sjimharris   // The current_dsm_descriptor points to the next location in the buffer
443230557Sjimharris   // Get the remaining bytes from the last translated descriptor
444230557Sjimharris   // to the end of the 4k buffer.
445230557Sjimharris   dsm_remainder_bytes = sequence->device->logical_block_size;
446230557Sjimharris   dsm_remainder_bytes -= (U32)((POINTER_UINT)unmap_process_state->current_dsm_descriptor &
447230557Sjimharris                                (sequence->device->logical_block_size-1));
448230557Sjimharris
449230557Sjimharris   // If there was no remainder, the complete buffer was filled in.
450230557Sjimharris   if (dsm_remainder_bytes != sequence->device->logical_block_size)
451230557Sjimharris   {
452230557Sjimharris       // Add on the remaining unfilled blocks
453230557Sjimharris       dsm_remainder_bytes += (sequence->device->logical_block_size * (max_dsm_blocks - dsm_blocks));
454230557Sjimharris
455230557Sjimharris       // According to ATA-8, if the DSM buffer is not completely filled with
456230557Sjimharris       // valid DSM descriptor data, the remaining portion of the
457230557Sjimharris       // buffer must be filled in with zeros.
458230557Sjimharris       memset((U8 *)unmap_process_state->current_dsm_descriptor, 0, dsm_remainder_bytes);
459230557Sjimharris   }
460230557Sjimharris
461230557Sjimharris   // Tell scic to utilize this sgl pair for write DMA processing of
462230557Sjimharris   // the SCSI UNMAP translation with the total number of bytes for this transfer
463230557Sjimharris   sati_cb_sge_write(unmap_process_state->unmap_buffer_sgl_pair,
464230557Sjimharris                     unmap_process_state->physical_unmap_buffer_low,
465230557Sjimharris                     unmap_process_state->physical_unmap_buffer_high,
466230557Sjimharris                     dsm_bytes);
467230557Sjimharris
468230557Sjimharris   // Construct the unmap ATA request
469230557Sjimharris   sati_unmap_construct(sequence,
470230557Sjimharris                        scsi_io,
471230557Sjimharris                        ata_io,
472230557Sjimharris                        dsm_blocks);
473230557Sjimharris
474230557Sjimharris   // Determine sequence next state based on whether there is more translation
475230557Sjimharris   // to complete
476230557Sjimharris   if (unmap_process_state->current_lba_count == 0)
477230557Sjimharris   {
478230557Sjimharris       // used for completion routine to determine if there is more processing
479230557Sjimharris       sequence->state = SATI_SEQUENCE_STATE_FINAL;
480230557Sjimharris   }
481230557Sjimharris   // This requests has already translated the SGL, have SCIC skip SGL translataion
482230557Sjimharris   return SATI_SUCCESS_SGL_TRANSLATED;
483230557Sjimharris}
484230557Sjimharris
485230557Sjimharris//******************************************************************************
486230557Sjimharris//* P U B L I C   M E T H O D S
487230557Sjimharris//******************************************************************************
488230557Sjimharris
489230557Sjimharris/**
490230557Sjimharris * @brief This method will handle termination of the
491230557Sjimharris *        SCSI unmap translation and frees previously allocated
492230557Sjimharris *        dma buffer.
493230557Sjimharris *
494230557Sjimharris * @return None
495230557Sjimharris */
496230557Sjimharrisvoid sati_unmap_terminate(
497230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
498230557Sjimharris   void                       * scsi_io,
499230557Sjimharris   void                       * ata_io
500230557Sjimharris)
501230557Sjimharris{
502230557Sjimharris   SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
503230557Sjimharris   unmap_process_state = &sequence->command_specific_data.unmap_process_state;
504230557Sjimharris
505230557Sjimharris   if (unmap_process_state->virtual_unmap_buffer != NULL)
506230557Sjimharris   {
507230557Sjimharris      sati_cb_free_dma_buffer(scsi_io, unmap_process_state->virtual_unmap_buffer);
508230557Sjimharris      unmap_process_state->virtual_unmap_buffer = NULL;
509230557Sjimharris   }
510230557Sjimharris}
511230557Sjimharris
512230557Sjimharris/**
513230557Sjimharris * @brief This method will translate the SCSI Unmap command
514230557Sjimharris *        into corresponding ATA commands.  Depending upon the capabilities
515230557Sjimharris *        supported by the target different ATA commands can be selected.
516230557Sjimharris *        Additionally, in some cases more than a single ATA command may
517230557Sjimharris *        be required.
518230557Sjimharris *
519230557Sjimharris * @return Indicate if the command translation succeeded.
520230557Sjimharris * @retval SATI_SUCCESS This is returned if the command translation was
521230557Sjimharris *         successful.
522230557Sjimharris * @retval SATI_COMPLETE This is returned if the command translation was
523230557Sjimharris *         successful and no ATA commands need to be set.
524230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
525230557Sjimharris *         sense data has been created as a result of something specified
526230557Sjimharris *         in the parameter data fields.
527230557Sjimharris */
528230557SjimharrisSATI_STATUS sati_unmap_translate_command(
529230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
530230557Sjimharris   void                       * scsi_io,
531230557Sjimharris   void                       * ata_io
532230557Sjimharris)
533230557Sjimharris{
534230557Sjimharris   SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
535230557Sjimharris   SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
536230557Sjimharris
537230557Sjimharris   unmap_process_state = &sequence->command_specific_data.unmap_process_state;
538230557Sjimharris
539230557Sjimharris   // Determine if this is the first step in the unmap sequence
540230557Sjimharris   if ( sequence->state == SATI_SEQUENCE_STATE_INITIAL )
541230557Sjimharris   {
542230557Sjimharris       status = sati_unmap_initial_processing(sequence,scsi_io,ata_io);
543230557Sjimharris       if (status != SATI_COMPLETE)
544230557Sjimharris       {
545230557Sjimharris          return status;
546230557Sjimharris       }
547230557Sjimharris   }
548230557Sjimharris   // Translate the next portion of the UNMAP request
549230557Sjimharris   return sati_unmap_process(sequence, scsi_io, ata_io);
550230557Sjimharris}
551230557Sjimharris
552230557Sjimharris/**
553230557Sjimharris * @brief This method will translate the ATA command register FIS
554230557Sjimharris *        response into an appropriate SCSI response for Unmap.
555230557Sjimharris *        For more information on the parameters passed to this method,
556230557Sjimharris *        please reference sati_translate_response().
557230557Sjimharris *
558230557Sjimharris * @return Indicate if the response translation succeeded.
559230557Sjimharris * @retval SATI_SUCCESS This is returned if the command translation was
560230557Sjimharris *         successful.
561230557Sjimharris * @retval SATI_COMPLETE This is returned if the command translation was
562230557Sjimharris *         successful and no ATA commands need to be set.
563230557Sjimharris * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
564230557Sjimharris *         sense data has been created as a result of something specified
565230557Sjimharris *         in the parameter data fields.
566230557Sjimharris */
567230557SjimharrisSATI_STATUS sati_unmap_translate_response(
568230557Sjimharris   SATI_TRANSLATOR_SEQUENCE_T * sequence,
569230557Sjimharris   void                       * scsi_io,
570230557Sjimharris   void                       * ata_io
571230557Sjimharris)
572230557Sjimharris{
573230557Sjimharris   U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
574230557Sjimharris   SATI_UNMAP_PROCESSING_STATE_T * unmap_process_state;
575230557Sjimharris   SATI_STATUS sati_status = SATI_COMPLETE;
576230557Sjimharris
577230557Sjimharris   unmap_process_state = &sequence->command_specific_data.unmap_process_state;
578230557Sjimharris
579230557Sjimharris   if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
580230557Sjimharris   {
581230557Sjimharris      sequence->state = SATI_SEQUENCE_STATE_FINAL;
582230557Sjimharris      sati_scsi_sense_data_construct(
583230557Sjimharris         sequence,
584230557Sjimharris         scsi_io,
585230557Sjimharris         SCSI_STATUS_CHECK_CONDITION,
586230557Sjimharris         SCSI_SENSE_ABORTED_COMMAND,
587230557Sjimharris         SCSI_ASC_NO_ADDITIONAL_SENSE,
588230557Sjimharris         SCSI_ASCQ_NO_ADDITIONAL_SENSE
589230557Sjimharris      );
590230557Sjimharris      // All done, terminate the translation
591230557Sjimharris      sati_unmap_terminate(sequence, scsi_io, ata_io);
592230557Sjimharris   }
593230557Sjimharris   else
594230557Sjimharris   {
595230557Sjimharris      if (sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE)
596230557Sjimharris      {
597230557Sjimharris          // All done, terminate the translation
598230557Sjimharris          sati_unmap_terminate(sequence, scsi_io, ata_io);
599230557Sjimharris      }
600230557Sjimharris      else
601230557Sjimharris      {
602230557Sjimharris          // Still translating
603230557Sjimharris          sati_status = SATI_SEQUENCE_STATE_INCOMPLETE;
604230557Sjimharris      }
605230557Sjimharris   }
606230557Sjimharris   return sati_status;
607230557Sjimharris}
608230557Sjimharris
609230557Sjimharris#endif // !defined(DISABLE_SATI_UNMAP)
610