xref: /freebsd/sys/dev/isci/scil/sati_reassign_blocks.c (revision 2e3507c25e42292b45a5482e116d278f5515d04d)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0
3  *
4  * This file is provided under a dual BSD/GPLv2 license.  When using or
5  * redistributing this file, you may do so under either license.
6  *
7  * GPL LICENSE SUMMARY
8  *
9  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of version 2 of the GNU General Public License as
13  * published by the Free Software Foundation.
14  *
15  * This program is distributed in the hope that it will be useful, but
16  * WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
23  * The full GNU General Public License is included in this distribution
24  * in the file called LICENSE.GPL.
25  *
26  * BSD LICENSE
27  *
28  * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
29  * All rights reserved.
30  *
31  * Redistribution and use in source and binary forms, with or without
32  * modification, are permitted provided that the following conditions
33  * are met:
34  *
35  *   * Redistributions of source code must retain the above copyright
36  *     notice, this list of conditions and the following disclaimer.
37  *   * Redistributions in binary form must reproduce the above copyright
38  *     notice, this list of conditions and the following disclaimer in
39  *     the documentation and/or other materials provided with the
40  *     distribution.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
43  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
44  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
45  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
46  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
47  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
49  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
50  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
51  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53  */
54 
55 #include <sys/cdefs.h>
56 /**
57  * @file
58  * @brief This file contains the method implementations required to
59  *        translate the SCSI reassign blocks command.
60  */
61 
62 #if !defined(DISABLE_SATI_REASSIGN_BLOCKS)
63 
64 #include <dev/isci/scil/sati_reassign_blocks.h>
65 #include <dev/isci/scil/sati_callbacks.h>
66 #include <dev/isci/scil/sati_move.h>
67 #include <dev/isci/scil/sati_write.h>
68 #include <dev/isci/scil/sati_translator_sequence.h>
69 #include <dev/isci/scil/sati_util.h>
70 #include <dev/isci/scil/intel_scsi.h>
71 
72 
73 //******************************************************************************
74 //* P R I V A T E   M E T H O D S
75 //******************************************************************************
76 // static SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T reassign_blocks_processing_state;
77 
78 /**
79  * @brief This method copies short 24bits LBA bytes to the command register
80  * @return Indicate if the method was successfully completed.
81  * @retval SATI_SUCCESS This is returned in all other cases.
82  */
83 static
84 void set_current_lba(U8 * lba, void  * ata_io)
85 {
86    U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
87 
88    sati_set_ata_lba_low(register_fis, lba[0]);
89    sati_set_ata_lba_mid(register_fis, lba[1]);
90    sati_set_ata_lba_high(register_fis, lba[2]);
91    sati_set_ata_device_head(register_fis, ATA_DEV_HEAD_REG_LBA_MODE_ENABLE | (lba[3] & 0x0F));
92 
93 
94 }
95 
96 /**
97  * @brief This method copies short 48bits LBA bytes to the command register
98  * @return Indicate if the method was successfully completed.
99  * @retval SATI_SUCCESS This is returned in all other cases.
100  */
101 static
102 void set_current_long_lba(U8 * lba, void  * ata_io)
103 {
104    U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
105 
106    sati_set_ata_lba_low(register_fis, lba[0]);
107    sati_set_ata_lba_mid(register_fis, lba[1]);
108    sati_set_ata_lba_high(register_fis, lba[2]);
109    sati_set_ata_lba_low_exp(register_fis, lba[3]);
110    sati_set_ata_lba_mid_exp(register_fis, lba[4]);
111    sati_set_ata_lba_high_exp(register_fis, lba[5]);
112 }
113 
114 /**
115  * @brief This method performs the SCSI VERIFY command translation
116  *        functionality.
117  *        This includes:
118  *        - setting the command register
119  *        - setting the device head register
120  *        - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
121  *        For more information on the parameters passed to this method,
122  *        please reference sati_translate_command().
123  *
124  * @return Indicate if the method was successfully completed.
125  * @retval SATI_SUCCESS This is returned in all other cases.
126  */
127 static
128 SATI_STATUS sati_reassign_blocks_verify_command(
129    SATI_TRANSLATOR_SEQUENCE_T * sequence,
130    void                       * scsi_io,
131    void                       * ata_io
132 )
133 {
134    U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
135 
136    sati_ata_non_data_command(ata_io, sequence);
137 
138    // Ensure the device supports the 48 bit feature set.
139    if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
140       sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS_EXT);
141    else
142       sati_set_ata_command(register_fis, ATA_READ_VERIFY_SECTORS);
143 
144    return SATI_SUCCESS;
145 }
146 
147 /**
148  * @brief This method performs the SCSI Write sector command translation
149  *        functionality.
150  *        This includes:
151  *        - setting the command register
152  *        - setting the device head register
153  *        - filling in fields in the SATI_TRANSLATOR_SEQUENCE object.
154  *        For more information on the parameters passed to this method,
155  *        please reference sati_translate_command().
156  *
157  * @return Indicate if the method was successfully completed.
158  * @retval SATI_SUCCESS This is returned in all other cases.
159  */
160 static
161 SATI_STATUS sati_reassign_blocks_write_command(
162    SATI_TRANSLATOR_SEQUENCE_T * sequence,
163    void                       * scsi_io,
164    void                       * ata_io
165 )
166 {
167    U8 * register_fis = sati_cb_get_h2d_register_fis_address(ata_io);
168 
169    sati_ata_non_data_command(ata_io, sequence);
170    sequence->data_direction = SATI_DATA_DIRECTION_OUT;
171 
172 //   sati_set_ata_sector_count(register_fis, 1);
173 //   status=sati_move_set_sector_count(sequence,scsi_io,ata_io,1,0);
174 
175    // Ensure the device supports the 48 bit feature set.
176    if (sequence->device->capabilities & SATI_DEVICE_CAP_48BIT_ENABLE)
177       sati_set_ata_command(register_fis, ATA_WRITE_DMA_EXT);
178    else
179       sati_set_ata_command(register_fis, ATA_WRITE_DMA);
180 
181    return SATI_SUCCESS; //sati_move_set_sector_count(sequence,scsi_io,ata_io,1,0);
182 }
183 
184 /**
185  * @brief This method performs the retrieving of parameter LBA praparation and setting
186  *        processing flags before/after calling SCSI Verify sector command.
187  * @return Indicate if the method was successfully completed.
188  * @retval SATI_SUCCESS This is returned in all other cases.
189  */
190 static
191 SATI_STATUS sati_reassign_blocks_verify_condition(
192    SATI_TRANSLATOR_SEQUENCE_T * sequence,
193    void     * scsi_io,
194    void     * ata_io
195 )
196 {
197    U8 current_lba_bytes[8] = {0,0,0,0,0,0,0,0};
198    U32 lba_offset;
199    U8 page_size;
200    U32 index;
201    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
202 
203    lba_offset = sequence->command_specific_data.reassign_blocks_process_state.lba_offset;
204    page_size = sequence->command_specific_data.reassign_blocks_process_state.lba_size;
205 
206    for(index = 0; index < page_size; index++)
207    {
208       sati_get_data_byte(sequence, scsi_io, lba_offset+index,   &current_lba_bytes[index]);
209    }
210 
211    if (page_size == 4)
212       set_current_lba(current_lba_bytes, ata_io);
213    else
214       set_current_long_lba(current_lba_bytes, ata_io);
215 
216    status = sati_reassign_blocks_verify_command(sequence, scsi_io, ata_io);
217    sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba++;
218    sequence->command_specific_data.reassign_blocks_process_state.ata_command_status = SATI_REASSIGN_BLOCKS_READY_TO_SEND;
219    return  status;
220 }
221 
222 /**
223  * @brief This method performs the retrieving of parameter LBA praparation and setting
224  *        processing flags before/after calling SCSI Write sector command.
225  * @return Indicate if the method was successfully completed.
226  * @retval SATI_SUCCESS This is returned in all other cases.
227  */
228 static
229 SATI_STATUS sati_reassign_blocks_write_condition(
230    SATI_TRANSLATOR_SEQUENCE_T * sequence,
231    void     * scsi_io,
232    void     * ata_io
233 )
234 {
235    U8 current_lba_bytes[8] = {0,0,0,0,0,0,0,0};
236    U32 lba_offset;
237    U8 page_size;
238    U32 index;
239    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
240 
241    lba_offset = sequence->command_specific_data.reassign_blocks_process_state.lba_offset;
242    page_size = sequence->command_specific_data.reassign_blocks_process_state.lba_size;
243 
244    for(index = 0; index < page_size; index++)
245    {
246       sati_get_data_byte(sequence, scsi_io, lba_offset+index,   &current_lba_bytes[index]);
247    }
248 
249    if (page_size == 4)
250       set_current_lba(current_lba_bytes, ata_io);
251    else
252       set_current_long_lba(current_lba_bytes, ata_io);
253 
254    status = sati_reassign_blocks_write_command(sequence, scsi_io, ata_io);
255    sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba++;
256    sequence->command_specific_data.reassign_blocks_process_state.ata_command_status = SATI_REASSIGN_BLOCKS_READY_TO_SEND;
257    return  status ;
258 }
259 
260 
261 /**
262  * @brief This method will perform the pre-processing of Reassign Blocks command and parameter.
263  */
264 static
265 void  sati_reassign_blocks_initial_processing(
266    SATI_TRANSLATOR_SEQUENCE_T * sequence,
267    void                       * scsi_io,
268    void                       * ata_io
269 )
270 {
271    U32 index;
272    U8 long_lba_bit;
273    U8 long_list_bit;
274    U8 lba_offset;
275    U8  page_size;
276    U32 data_transfer_length;
277    U8 header_bytes[4]={0,0,0,0};
278 
279    U8 * cdb = sati_cb_get_cdb_address(scsi_io);
280 
281    //A long LBA (LONGLBA) bit set to zero specifies that the REASSIGN BLOCKS defective LBA list contains four-byte LBAs.
282    //A LONGLBA bit set to one specifies that the REASSIGN BLOCKS defective LBA list contains eight-byte LBAs.
283    if ((sati_get_cdb_byte(cdb, 1) & SCSI_REASSIGN_BLOCKS_LONGLBA_BIT) == 0)
284    {
285       long_lba_bit=0;
286       page_size = 4; //beginning of lba list
287    }
288    else
289    {
290       long_lba_bit=1;
291       page_size = 8;
292    }
293 
294    //The long list (LONGLIST) bit specifies which parameter list header
295    if ((sati_get_cdb_byte(cdb, 1) & SCSI_REASSIGN_BLOCKS_LONGLIST_BIT) == 0)
296    {
297       long_list_bit=0;
298    }
299    else
300    {
301       long_list_bit=1;
302    }
303 
304    sequence->allocation_length = 4; //Pre-set allocation_length so that the header can be retrieved
305 
306    //Get 4 bytes for headers (byte 2 & byte 3 for short header; long header all 4 bytes)
307    for(index = 0; index < 4; index++)
308    {
309       sati_get_data_byte(sequence, scsi_io, index,   &header_bytes[index]);
310    }
311 
312    lba_offset = 4; //beginning of lba list
313 
314    if (long_list_bit==0)
315    {
316       //Header byte 2 and 3 is the parameter list length
317       data_transfer_length = (header_bytes[2]<<8) + header_bytes[3] + lba_offset;
318    }
319    else
320    {
321       //Header byte 0, 1, 2 and 3 contain the parameter list length
322       data_transfer_length = (header_bytes[0]<<24) + (header_bytes[1]<<16) +
323          (header_bytes[2]<<8) + header_bytes[3] + lba_offset;
324    }
325 
326    sequence->allocation_length = data_transfer_length;
327 
328    //Initialized the global processing state
329    sequence->command_specific_data.reassign_blocks_process_state.lba_size   =     page_size;
330    sequence->command_specific_data.reassign_blocks_process_state.lba_offset =     lba_offset;
331    sequence->command_specific_data.reassign_blocks_process_state.ata_command_sent_for_current_lba = 0;
332    sequence->command_specific_data.reassign_blocks_process_state.block_lists_size       = data_transfer_length  -  lba_offset;
333    sequence->command_specific_data.reassign_blocks_process_state.size_of_data_processed = 0;
334    sequence->command_specific_data.reassign_blocks_process_state.current_lba_processed  = FALSE;
335    sequence->command_specific_data.reassign_blocks_process_state.ata_command_status     = SATI_REASSIGN_BLOCKS_COMMAND_FAIL;
336 }
337 
338 /**
339  * @brief This method will get the data size of not yet processed data.
340  *
341  * @param[in] lba_process_state This parameter points to the processing state fields
342  *            of current block lba.
343  *
344  * @return This method returns the sizeof not yet processed data.
345  */
346 static
347 U32 sati_reassign_blocks_unprocessed_data_size(
348    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * lba_process_state
349 )
350 {
351    U32 unprocessed_data_size;
352 
353    if(lba_process_state->block_lists_size >= lba_process_state->size_of_data_processed)
354    {
355       unprocessed_data_size = lba_process_state->block_lists_size -
356          lba_process_state->size_of_data_processed;
357    }
358    else
359    {
360       unprocessed_data_size = 0;
361    }
362 
363    return unprocessed_data_size;
364 }
365 
366 
367 /**
368  * @brief This method will check verify the sector and issue multiple ATA set feature commands to complete the translation.
369  *
370  * @param[in] reassign_blocks_process_state This parameter points to the processing state fields
371  *            of current lba block.
372  *
373  *
374  * @return Indicate if the translation was successful.
375  * @retval SATI_SUCCESS
376  * @retval SATI_COMPLETE
377  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
378  */
379 static
380 SATI_STATUS sati_reassign_blocks_process_each_lba(
381    SATI_TRANSLATOR_SEQUENCE_T * sequence,
382    void                       * scsi_io,
383    void                       * ata_io
384    )
385 {
386    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
387    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
388 
389    reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
390 
391    if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 0)&&
392       (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_FAIL))
393    {
394       reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
395       status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
396    }
397    else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 0)&&
398       (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS))
399    {
400       // point to next lba
401       reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
402       reassign_blocks_process_state->lba_offset += reassign_blocks_process_state->lba_size;
403       status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
404    }
405    else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 1)&&
406       (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_FAIL))
407    {
408       reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
409       status = sati_reassign_blocks_write_condition(sequence, scsi_io, ata_io);
410    }
411    else if((reassign_blocks_process_state->ata_command_sent_for_current_lba == 2) &&
412       (reassign_blocks_process_state->ata_command_status == SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS))
413    {
414       reassign_blocks_process_state->size_of_data_processed += reassign_blocks_process_state->lba_size;
415       status = sati_reassign_blocks_verify_condition(sequence, scsi_io, ata_io);
416    }
417    else //commands sent is 2; SATI_REASSIGN_BLOCKS_COMMAND_FAIL
418    {
419       status = SATI_FAILURE_CHECK_RESPONSE_DATA;
420    }
421 
422    return status;
423 }
424 
425 /**
426  * @brief This method will process the each lba.
427  *
428  * @param[in] reassign_blocks_process_state This parameter points to the processing state fields
429  *            of current lba.
430  *
431  * @return Indicate if the translation was successful.
432  * @retval SATI_SUCCESS
433  * @retval SATI_COMPLETE
434  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA
435  */
436 static
437 SATI_STATUS sati_reassign_blocks_process(
438    SATI_TRANSLATOR_SEQUENCE_T * sequence,
439    void                       * scsi_io,
440    void                       * ata_io
441 )
442 {
443    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
444 
445    U32 page_size = 0; // in bytes
446    U32 size_of_data_to_be_processed;
447    U32 lba_offset;
448    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
449 
450    reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
451 
452    lba_offset = reassign_blocks_process_state->lba_offset;
453    page_size  = reassign_blocks_process_state->lba_size;
454 
455 
456    if(sati_reassign_blocks_unprocessed_data_size(reassign_blocks_process_state) < page_size)
457    {
458       return status;
459    }
460 
461    // Any more lba blocks? If not, done.
462    if(reassign_blocks_process_state->block_lists_size ==
463       reassign_blocks_process_state->size_of_data_processed)
464    {
465       sequence->state = SATI_SEQUENCE_STATE_FINAL;
466       status = SATI_COMPLETE;
467    }
468    //start processing next lba
469    else
470    {
471       size_of_data_to_be_processed = reassign_blocks_process_state->block_lists_size
472          - reassign_blocks_process_state->size_of_data_processed;
473 
474       status = sati_reassign_blocks_process_each_lba(sequence, scsi_io, ata_io);
475 
476    }
477 
478    return status;
479 }
480 
481 //******************************************************************************
482 //* P U B L I C   M E T H O D S
483 //******************************************************************************
484 
485 /**
486  * @brief This method will translate the SCSI Reassign Blocks command
487  *        into corresponding ATA commands.  Depending upon the capabilities
488  *        supported by the target different ATA commands can be selected.
489  *        Additionally, in some cases more than a single ATA command may
490  *        be required.
491  *
492  * @return Indicate if the command translation succeeded.
493  * @retval SCI_SUCCESS This is returned if the command translation was
494  *         successful.
495  * @retval SCI_COMPLETE This is returned if the command translation was
496  *         successful and no ATA commands need to be set.
497  * @retval SATI_FAILURE_CHECK_RESPONSE_DATA This value is returned if
498  *         sense data has been created as a result of something specified
499  *         in the parameter data fields.
500  */
501 SATI_STATUS sati_reassign_blocks_translate_command(
502    SATI_TRANSLATOR_SEQUENCE_T * sequence,
503    void                       * scsi_io,
504    void                       * ata_io
505 )
506 {
507    SATI_STATUS status = SATI_FAILURE_CHECK_RESPONSE_DATA;
508    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
509 
510    reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
511 
512    sequence->type = SATI_SEQUENCE_REASSIGN_BLOCKS;
513 
514    //Initial processing if
515    if ( sequence->state != SATI_SEQUENCE_STATE_INCOMPLETE )
516    {
517       sati_reassign_blocks_initial_processing(
518          sequence,
519          scsi_io,
520          ata_io
521       );
522    }
523 
524    // start processing current lba
525    if(reassign_blocks_process_state->current_lba_processed)
526    {
527       reassign_blocks_process_state->ata_command_sent_for_current_lba = 0;
528       reassign_blocks_process_state->current_lba_processed = FALSE;
529    }
530 
531    status = sati_reassign_blocks_process(sequence, scsi_io, ata_io);
532 
533    if(reassign_blocks_process_state->block_lists_size ==
534       reassign_blocks_process_state->size_of_data_processed)
535    {
536       // Done this lba
537       sequence->state = SATI_SEQUENCE_STATE_FINAL;
538    }
539    else
540    {
541       sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
542    }
543 
544    if(status == SATI_FAILURE_CHECK_RESPONSE_DATA)
545    {
546       sequence->state = SATI_SEQUENCE_STATE_FINAL;
547       sati_scsi_sense_data_construct(
548          sequence,
549          scsi_io,
550          SCSI_STATUS_CHECK_CONDITION,
551          SCSI_SENSE_MEDIUM_ERROR,
552          SCSI_ASC_UNRECOVERED_READ_ERROR,
553          SCSI_ASCQ_UNRECOVERED_READ_ERROR_AUTO_REALLOCATE_FAIL
554       );
555    }
556 
557    return status;
558 }
559 
560 /**
561  * @brief This method will translate the ATA command register FIS
562  *        response into an appropriate SCSI response for Reassign Blocks
563  *        For more information on the parameters passed to this method,
564  *        please reference sati_translate_response().
565  *
566  * @return Indicate if the response translation succeeded.
567  * @retval SCI_SUCCESS This is returned if the data translation was
568  *         successful.
569  */
570 SATI_STATUS sati_reassign_blocks_translate_response(
571    SATI_TRANSLATOR_SEQUENCE_T * sequence,
572    void                       * scsi_io,
573    void                       * ata_io
574 )
575 {
576    U8 * register_fis = sati_cb_get_d2h_register_fis_address(ata_io);
577    SATI_REASSIGN_BLOCKS_PROCESSING_STATE_T * reassign_blocks_process_state;
578 
579    reassign_blocks_process_state = &sequence->command_specific_data.reassign_blocks_process_state;
580 
581    if (sati_get_ata_status(register_fis) & ATA_STATUS_REG_ERROR_BIT)
582    {
583       reassign_blocks_process_state->ata_command_status = SATI_REASSIGN_BLOCKS_COMMAND_FAIL;
584 
585       //Checking for the number of ATA commands attempted on current LBA, stop
586       //the seaquence after 2 commands have returned errors.
587       if(reassign_blocks_process_state->ata_command_sent_for_current_lba < 2)
588       {
589          sequence->state = SATI_SEQUENCE_STATE_INCOMPLETE;
590          reassign_blocks_process_state->size_of_data_processed -= reassign_blocks_process_state->lba_size;
591          return SATI_SEQUENCE_INCOMPLETE;
592       }
593       else
594       {
595          sati_scsi_sense_data_construct(
596             sequence,
597             scsi_io,
598             SCSI_STATUS_CHECK_CONDITION,
599             SCSI_SENSE_MEDIUM_ERROR,
600             SCSI_ASC_UNRECOVERED_READ_ERROR,
601             SCSI_ASCQ_UNRECOVERED_READ_ERROR_AUTO_REALLOCATE_FAIL
602          );
603       }
604 
605       return SATI_FAILURE_CHECK_RESPONSE_DATA;
606    }
607    else
608    {
609       reassign_blocks_process_state->ata_command_status = SATI_REASSIGN_BLOCKS_COMMAND_SUCCESS;
610       if (reassign_blocks_process_state->ata_command_sent_for_current_lba != 2)
611          reassign_blocks_process_state->current_lba_processed = TRUE;
612 
613       if (sequence->state == SATI_SEQUENCE_STATE_INCOMPLETE)
614       {
615          return SATI_SEQUENCE_INCOMPLETE;
616       }
617    }
618    return SATI_COMPLETE;
619 }
620 
621 #endif // !defined(DISABLE_SATI_REASSIGN_BLOCKS)
622 
623